]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge current mainline tree into linux-omap tree
authorTony Lindgren <tony@atomide.com>
Tue, 7 Oct 2008 11:27:17 +0000 (14:27 +0300)
committerTony Lindgren <tony@atomide.com>
Tue, 7 Oct 2008 11:27:17 +0000 (14:27 +0300)
Merge branches 'master' and 'linus'

478 files changed:
Documentation/arm/OMAP/README [new file with mode: 0644]
Documentation/arm/OMAP/gpio [new file with mode: 0644]
Documentation/gpio.txt
Makefile
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/head-omap.S [new file with mode: 0644]
arch/arm/configs/n800_defconfig [new file with mode: 0644]
arch/arm/configs/omap2_evm_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_beagle_defconfig [new file with mode: 0644]
arch/arm/configs/omap3_evm_defconfig [new file with mode: 0644]
arch/arm/configs/omap_3430sdp_defconfig [new file with mode: 0644]
arch/arm/configs/omap_h3_1710_defconfig [new file with mode: 0644]
arch/arm/configs/omap_ldp_defconfig [new file with mode: 0644]
arch/arm/configs/overo_defconfig [new file with mode: 0644]
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/setup.h
arch/arm/include/asm/system.h
arch/arm/kernel/setup.c
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-h2-mmc.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3-mmc.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-palmte.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-sx1-mmc.c
arch/arm/mach-omap1/board-sx1.c
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/id.c
arch/arm/mach-omap1/mcbsp.c
arch/arm/mach-omap1/mmu.c [new file with mode: 0644]
arch/arm/mach-omap1/mmu.h [new file with mode: 0644]
arch/arm/mach-omap1/serial.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-2430sdp-flash.c [new file with mode: 0644]
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp-flash.c [new file with mode: 0644]
arch/arm/mach-omap2/board-3430sdp.c [new file with mode: 0644]
arch/arm/mach-omap2/board-apollon-keys.c [new file with mode: 0644]
arch/arm/mach-omap2/board-apollon-mmc.c [new file with mode: 0644]
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4-mmc.c [new file with mode: 0644]
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-ldp.c [new file with mode: 0644]
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-camera.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-usb.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800.c [new file with mode: 0644]
arch/arm/mach-omap2/board-n800.h [new file with mode: 0644]
arch/arm/mach-omap2/board-n810.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap2evm.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap3beagle.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap3evm-flash.c [new file with mode: 0644]
arch/arm/mach-omap2/board-omap3evm.c [new file with mode: 0644]
arch/arm/mach-omap2/board-overo.c [new file with mode: 0644]
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock24xx.c
arch/arm/mach-omap2/clock24xx.h
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/clock34xx.h
arch/arm/mach-omap2/clockdomain.c [new file with mode: 0644]
arch/arm/mach-omap2/clockdomains.h [new file with mode: 0644]
arch/arm/mach-omap2/cm-regbits-24xx.h
arch/arm/mach-omap2/cm-regbits-34xx.h
arch/arm/mach-omap2/cm.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/hsmmc.c [new file with mode: 0644]
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/irq.c
arch/arm/mach-omap2/mailbox.c
arch/arm/mach-omap2/mcbsp.c
arch/arm/mach-omap2/memory.h [deleted file]
arch/arm/mach-omap2/mmu.c [new file with mode: 0644]
arch/arm/mach-omap2/mmu.h [new file with mode: 0644]
arch/arm/mach-omap2/mux.c
arch/arm/mach-omap2/pm-debug.c [new file with mode: 0644]
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/pm.h [new file with mode: 0644]
arch/arm/mach-omap2/pm24xx.c [new file with mode: 0644]
arch/arm/mach-omap2/pm34xx.c [new file with mode: 0644]
arch/arm/mach-omap2/powerdomain.c [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains.h [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains24xx.h [new file with mode: 0644]
arch/arm/mach-omap2/powerdomains34xx.h [new file with mode: 0644]
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm-regbits-24xx.h
arch/arm/mach-omap2/prm-regbits-34xx.h
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h [new file with mode: 0644]
arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h [new file with mode: 0644]
arch/arm/mach-omap2/sdrc.c [new file with mode: 0644]
arch/arm/mach-omap2/sdrc2xxx.c [moved from arch/arm/mach-omap2/memory.c with 71% similarity]
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep24xx.S [moved from arch/arm/mach-omap2/sleep.S with 85% similarity]
arch/arm/mach-omap2/sleep34xx.S [new file with mode: 0644]
arch/arm/mach-omap2/smartreflex.c [new file with mode: 0644]
arch/arm/mach-omap2/smartreflex.h [new file with mode: 0644]
arch/arm/mach-omap2/sram242x.S
arch/arm/mach-omap2/sram243x.S
arch/arm/mach-omap2/sram34xx.S [new file with mode: 0644]
arch/arm/mach-omap2/timer-gp.c
arch/arm/mach-omap2/usb-ehci.c [new file with mode: 0644]
arch/arm/mach-omap2/usb-musb.c [new file with mode: 0644]
arch/arm/mach-omap2/usb-tusb6010.c
arch/arm/mm/Kconfig
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/cpu-omap.c
arch/arm/plat-omap/devices.c
arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/gpio-switch.c [new file with mode: 0644]
arch/arm/plat-omap/gpio.c
arch/arm/plat-omap/i2c.c
arch/arm/plat-omap/include/mach/aic23.h
arch/arm/plat-omap/include/mach/board-2430sdp.h
arch/arm/plat-omap/include/mach/board-3430sdp.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-apollon.h
arch/arm/plat-omap/include/mach/board-h2.h
arch/arm/plat-omap/include/mach/board-h3.h
arch/arm/plat-omap/include/mach/board-h4.h
arch/arm/plat-omap/include/mach/board-ldp.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-nokia.h
arch/arm/plat-omap/include/mach/board-omap2evm.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-omap3beagle.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-omap3evm.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board-overo.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/board.h
arch/arm/plat-omap/include/mach/clock.h
arch/arm/plat-omap/include/mach/clockdomain.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/common.h
arch/arm/plat-omap/include/mach/control.h
arch/arm/plat-omap/include/mach/cpu.h
arch/arm/plat-omap/include/mach/debug-macro.S
arch/arm/plat-omap/include/mach/dsp.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/dsp_common.h
arch/arm/plat-omap/include/mach/entry-macro.S
arch/arm/plat-omap/include/mach/fpga.h
arch/arm/plat-omap/include/mach/gpio-switch.h
arch/arm/plat-omap/include/mach/gpio.h
arch/arm/plat-omap/include/mach/gpmc.h
arch/arm/plat-omap/include/mach/hardware.h
arch/arm/plat-omap/include/mach/hsmmc.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/io.h
arch/arm/plat-omap/include/mach/irqs.h
arch/arm/plat-omap/include/mach/keypad.h
arch/arm/plat-omap/include/mach/mailbox.h
arch/arm/plat-omap/include/mach/mcbsp.h
arch/arm/plat-omap/include/mach/memory.h
arch/arm/plat-omap/include/mach/mmc.h
arch/arm/plat-omap/include/mach/mmu.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/mux.h
arch/arm/plat-omap/include/mach/omap-alsa.h
arch/arm/plat-omap/include/mach/omap1510.h
arch/arm/plat-omap/include/mach/omap16xx.h
arch/arm/plat-omap/include/mach/omap24xx.h
arch/arm/plat-omap/include/mach/omap34xx.h
arch/arm/plat-omap/include/mach/omapfb.h
arch/arm/plat-omap/include/mach/onenand.h
arch/arm/plat-omap/include/mach/pm.h
arch/arm/plat-omap/include/mach/powerdomain.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/prcm.h
arch/arm/plat-omap/include/mach/sdrc.h
arch/arm/plat-omap/include/mach/serial.h
arch/arm/plat-omap/include/mach/sram.h
arch/arm/plat-omap/include/mach/sti.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/system.h
arch/arm/plat-omap/include/mach/timex.h
arch/arm/plat-omap/include/mach/usb-ehci.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/usb-musb.h [new file with mode: 0644]
arch/arm/plat-omap/include/mach/usb.h
arch/arm/plat-omap/include/mach/vmalloc.h
arch/arm/plat-omap/io.c [new file with mode: 0644]
arch/arm/plat-omap/mcbsp.c
arch/arm/plat-omap/mmu.c [new file with mode: 0644]
arch/arm/plat-omap/sram.c
drivers/Makefile
drivers/bluetooth/Kconfig
drivers/bluetooth/Makefile
drivers/bluetooth/brf6150.c [new file with mode: 0644]
drivers/bluetooth/brf6150.h [new file with mode: 0644]
drivers/bluetooth/hci_h4p/Makefile [new file with mode: 0644]
drivers/bluetooth/hci_h4p/core.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw-csr.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw-ti.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/fw.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/hci_h4p.h [new file with mode: 0644]
drivers/bluetooth/hci_h4p/sysfs.c [new file with mode: 0644]
drivers/bluetooth/hci_h4p/uart.c [new file with mode: 0644]
drivers/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-headset.c [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/hw_random/omap-rng.c
drivers/crypto/Kconfig
drivers/crypto/Makefile
drivers/crypto/omap-sha1-md5.c [new file with mode: 0644]
drivers/dsp/dspgateway/Kconfig [new file with mode: 0644]
drivers/dsp/dspgateway/Makefile [new file with mode: 0644]
drivers/dsp/dspgateway/dsp.h [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_common.c [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_core.c [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_ctl.c [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_ctl_core.c [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_mbcmd.h [new file with mode: 0644]
drivers/dsp/dspgateway/dsp_mem.c [new file with mode: 0644]
drivers/dsp/dspgateway/error.c [new file with mode: 0644]
drivers/dsp/dspgateway/hardware_dsp.h [new file with mode: 0644]
drivers/dsp/dspgateway/ipbuf.c [new file with mode: 0644]
drivers/dsp/dspgateway/ipbuf.h [new file with mode: 0644]
drivers/dsp/dspgateway/mblog.c [new file with mode: 0644]
drivers/dsp/dspgateway/mmu.h [new file with mode: 0644]
drivers/dsp/dspgateway/omap1_dsp.h [new file with mode: 0644]
drivers/dsp/dspgateway/omap2_dsp.h [new file with mode: 0644]
drivers/dsp/dspgateway/proclist.h [new file with mode: 0644]
drivers/dsp/dspgateway/task.c [new file with mode: 0644]
drivers/dsp/dspgateway/taskwatch.c [new file with mode: 0644]
drivers/dsp/dspgateway/uaccess_dsp.S [new file with mode: 0644]
drivers/dsp/dspgateway/uaccess_dsp.h [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpiolib.c
drivers/gpio/twl4030-gpio.c [new file with mode: 0644]
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/omap34xx_temp.c [new file with mode: 0644]
drivers/hwmon/tsc210x_sensors.c [new file with mode: 0644]
drivers/i2c/Kconfig
drivers/i2c/busses/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/lp5521.c [new file with mode: 0644]
drivers/i2c/chips/menelaus.c
drivers/i2c/chips/tlv320aic23.c [new file with mode: 0644]
drivers/i2c/chips/tsl2563.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-madc.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-power.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-poweroff.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-pwrbutton.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-pwrirq.c [new file with mode: 0644]
drivers/i2c/chips/twl4030-usb.c [new file with mode: 0644]
drivers/i2c/i2c-core.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/innovator_ps2.c [new file with mode: 0644]
drivers/input/keyboard/lm8323.c [new file with mode: 0644]
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/omap-twl4030keypad.c [new file with mode: 0644]
drivers/input/keyboard/tsc2301_kp.c [new file with mode: 0644]
drivers/input/keyboard/twl4030-keypad.h [new file with mode: 0644]
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/tsc2005.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2102_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc210x_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2301_ts.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-omap-pwm.c [new file with mode: 0644]
drivers/leds/leds-omap.c [new file with mode: 0644]
drivers/media/common/tuners/tea5761.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-tea5761.c [new file with mode: 0644]
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/omap/Kconfig [new file with mode: 0644]
drivers/media/video/omap/Makefile [new file with mode: 0644]
drivers/media/video/omap/camera_core.c [new file with mode: 0644]
drivers/media/video/omap/camera_core.h [new file with mode: 0644]
drivers/media/video/omap/camera_hw_if.h [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.c [new file with mode: 0644]
drivers/media/video/omap/omap16xxcam.h [new file with mode: 0644]
drivers/media/video/omap24xxcam-dma.c [new file with mode: 0644]
drivers/media/video/omap24xxcam.c [new file with mode: 0644]
drivers/media/video/omap24xxcam.h [new file with mode: 0644]
drivers/media/video/ov9640.c [new file with mode: 0644]
drivers/media/video/ov9640.h [new file with mode: 0644]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/twl4030-core.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/sti/Makefile [new file with mode: 0644]
drivers/misc/sti/sdti.c [new file with mode: 0644]
drivers/misc/sti/sti-console.c [new file with mode: 0644]
drivers/misc/sti/sti-fifo.c [new file with mode: 0644]
drivers/misc/sti/sti-netlink.c [new file with mode: 0644]
drivers/misc/sti/sti.c [new file with mode: 0644]
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c [new file with mode: 0644]
drivers/mtd/cmdlinepart.c
drivers/mtd/maps/omap-toto-flash.c
drivers/mtd/maps/omap_nor.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/omap-hw.c [new file with mode: 0644]
drivers/mtd/nand/omap-nand-flash.c [new file with mode: 0644]
drivers/mtd/nand/omap2.c [new file with mode: 0644]
drivers/mtd/onenand/Kconfig
drivers/mtd/onenand/Makefile
drivers/mtd/onenand/omap2.c [new file with mode: 0644]
drivers/net/Kconfig
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/omap-ir.c [new file with mode: 0644]
drivers/net/smc911x.h
drivers/net/smc91x.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/bq27x00_battery.c [new file with mode: 0644]
drivers/power/twl4030_bci_battery.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-twl4030.c [new file with mode: 0644]
drivers/serial/8250.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/omap2_mcspi.c
drivers/spi/omap_uwire.c
drivers/spi/tsc2101.c [new file with mode: 0644]
drivers/spi/tsc2102.c [new file with mode: 0644]
drivers/spi/tsc210x.c [new file with mode: 0644]
drivers/spi/tsc2301-core.c [new file with mode: 0644]
drivers/spi/tsc2301-mixer.c [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/gadget/Kconfig
drivers/usb/gadget/omap_udc.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-omap.c [new file with mode: 0644]
drivers/usb/host/ehci-omap.h [new file with mode: 0644]
drivers/usb/host/ohci-omap.c
drivers/usb/musb/davinci.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010_omap.c
drivers/video/omap/Kconfig
drivers/video/omap/Makefile
drivers/video/omap/blizzard.c
drivers/video/omap/dispc.c
drivers/video/omap/dispc.h
drivers/video/omap/lcd_2430sdp.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_h4.c
drivers/video/omap/lcd_inn1610.c
drivers/video/omap/lcd_mipid.c [new file with mode: 0644]
drivers/video/omap/lcd_omap2evm.c [new file with mode: 0644]
drivers/video/omap/lcd_omap3beagle.c [new file with mode: 0644]
drivers/video/omap/lcd_omap3evm.c [new file with mode: 0644]
drivers/video/omap/lcd_osk.c
drivers/video/omap/lcd_overo.c [new file with mode: 0644]
drivers/video/omap/lcd_p2.c [new file with mode: 0644]
drivers/video/omap/lcd_sx1.c
drivers/video/omap/lcdc.c
drivers/video/omap/lcdc.h
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap/sossi.c
drivers/w1/masters/Kconfig
drivers/w1/masters/Makefile
drivers/w1/masters/omap_hdq.c [new file with mode: 0644]
drivers/w1/slaves/Kconfig
drivers/w1/slaves/Makefile
drivers/w1/slaves/w1_bq27000.c [new file with mode: 0644]
drivers/w1/w1.h
drivers/w1/w1_io.c
drivers/watchdog/Kconfig
drivers/watchdog/omap_wdt.c
drivers/watchdog/omap_wdt.h
include/asm-arm/.gitignore
include/asm-arm/hardware/tsc2101.h [new file with mode: 0644]
include/asm-generic/gpio.h
include/linux/connector.h
include/linux/i2c-id.h
include/linux/i2c/lm8323.h [new file with mode: 0644]
include/linux/i2c/menelaus.h [new file with mode: 0644]
include/linux/i2c/twl4030-madc.h [new file with mode: 0644]
include/linux/i2c/twl4030.h [new file with mode: 0644]
include/linux/kfifo.h
include/linux/mtd/nand.h
include/linux/mtd/onenand_regs.h
include/linux/netfilter_ipv4/ipt_IDLETIMER.h [new file with mode: 0644]
include/linux/spi/ads7846.h
include/linux/spi/tsc2005.h [new file with mode: 0644]
include/linux/spi/tsc2101.h [new file with mode: 0644]
include/linux/spi/tsc2102.h [new file with mode: 0644]
include/linux/spi/tsc210x.h [new file with mode: 0644]
include/linux/spi/tsc2301.h [new file with mode: 0644]
kernel/kfifo.c
kernel/printk.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ipt_IDLETIMER.c [new file with mode: 0644]
security/Kconfig
security/Makefile
security/lowmem.c [new file with mode: 0644]
sound/arm/Kconfig
sound/arm/Makefile
sound/arm/omap/Makefile [new file with mode: 0644]
sound/arm/omap/eac.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-aic23.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-dma.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-sx1.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101-mixer.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2101.h [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102-mixer.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.c [new file with mode: 0644]
sound/arm/omap/omap-alsa-tsc2102.h [new file with mode: 0644]
sound/arm/omap/omap-alsa.c [new file with mode: 0644]
sound/oss/Makefile
sound/oss/omap-audio-aic23.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.c [new file with mode: 0644]
sound/oss/omap-audio-dma-intfc.h [new file with mode: 0644]
sound/oss/omap-audio-tsc2101.c [new file with mode: 0644]
sound/oss/omap-audio.c [new file with mode: 0644]
sound/oss/omap-audio.h [new file with mode: 0644]
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/twl4030.c [new file with mode: 0644]
sound/soc/codecs/twl4030.h [new file with mode: 0644]
sound/soc/omap/Kconfig
sound/soc/omap/Makefile
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/overo.c [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 18022e249c53dc1ad991d74d160551fa32f32070..8a7c45956d2412d69a26f8de991db19ed25a838f 100644 (file)
@@ -264,7 +264,7 @@ map between them using calls like:
        /* map GPIO numbers to IRQ numbers */
        int gpio_to_irq(unsigned gpio);
 
-       /* map IRQ numbers to GPIO numbers */
+       /* map IRQ numbers to GPIO numbers (avoid using this) */
        int irq_to_gpio(unsigned irq);
 
 Those return either the corresponding number in the other namespace, or
@@ -284,7 +284,8 @@ system wakeup capabilities.
 
 Non-error values returned from irq_to_gpio() would most commonly be used
 with gpio_get_value(), for example to initialize or update driver state
-when the IRQ is edge-triggered.
+when the IRQ is edge-triggered.  Note that some platforms don't support
+this reverse mapping, so you should avoid using it.
 
 
 Emulating Open Drain Signals
index ce9eceb2538e39b2356aff71e625ecb7e7752d83..cd253ffa7516e69d9314780ebd4d967ae70d9413 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,9 @@ NAME = Rotary Wombat
 # 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.
 #
@@ -171,6 +174,8 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
                                  -e s/sh.*/sh/ )
 
+SUBARCH := arm
+
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
 #
@@ -191,7 +196,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
 export KBUILD_BUILDHOST := $(SUBARCH)
 ARCH           ?= $(SUBARCH)
-CROSS_COMPILE  ?=
+CROSS_COMPILE  ?= arm-linux-
 
 # Architecture as present in compile.h
 UTS_MACHINE    := $(ARCH)
index 70dba16689077dc0440cf12cc607f000bd5bdbdf..aa475d93549a1f3a07bb8ee61dffc24e40e762e8 100644 (file)
@@ -1234,6 +1234,11 @@ source "drivers/regulator/Kconfig"
 
 source "drivers/uio/Kconfig"
 
+if ARCH_OMAP
+source "drivers/cbus/Kconfig"
+source "drivers/dsp/dspgateway/Kconfig"
+endif
+
 endmenu
 
 source "fs/Kconfig"
index 703a44fa0f9b7c70814c17ab21e613eafcf4655a..94003142082c6a64182059cb962d6eb559583d55 100644 (file)
@@ -47,7 +47,7 @@ comma = ,
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v7)                :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7a,-march=armv5t -Wa$(comma)-march=armv7a)
+arch-$(CONFIG_CPU_32v7)                :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
 arch-$(CONFIG_CPU_32v6)                :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 # Only override the compiler option if ARMv6. The ARMv6K extensions are
 # always available in ARMv7
@@ -118,6 +118,7 @@ endif
  machine-$(CONFIG_ARCH_IXP23XX)    := ixp23xx
  machine-$(CONFIG_ARCH_OMAP1)     := omap1
  machine-$(CONFIG_ARCH_OMAP2)     := omap2
+ machine-$(CONFIG_ARCH_OMAP3)     := omap2
     plat-$(CONFIG_ARCH_OMAP)      := omap
  machine-$(CONFIG_ARCH_S3C2410)           := s3c2410 s3c2400 s3c2412 s3c2440 s3c2442 s3c2443
     plat-$(CONFIG_PLAT_S3C24XX)           := s3c24xx
index 94462a097f86697ce51558bd9389a4886b904318..b6f850223cf7c99b043ec46c9a395e01e1375e2a 100644 (file)
@@ -44,6 +44,10 @@ ifeq ($(CONFIG_PXA_SHARPSL),y)
 OBJS           += head-sharpsl.o
 endif
 
+ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y)
+OBJS           += head-omap.o
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
 ifeq ($(CONFIG_CPU_CP15),y)
 OBJS           += big-endian.o
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/n800_defconfig b/arch/arm/configs/n800_defconfig
new file mode 100644 (file)
index 0000000..98b4db0
--- /dev/null
@@ -0,0 +1,1595 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-omap1
+# Mon Apr 28 10:58:14 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+CONFIG_OMAP_COMPONENT_VERSION=y
+CONFIG_OMAP_GPIO_SWITCH=y
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+CONFIG_OMAP_MMU_FWK=y
+CONFIG_OMAP_MBOX_FWK=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+CONFIG_ARCH_OMAP2420=y
+# CONFIG_ARCH_OMAP2430 is not set
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_NOKIA_N800=y
+CONFIG_MACH_NOKIA_N810=y
+CONFIG_MACH_OMAP2_TUSB6010=y
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_APOLLON is not set
+# CONFIG_MACH_OMAP_2430OSK is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="root=1f03 rootfstype=jffs2"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_IDLETIMER=y
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBRF6150 is not set
+# CONFIG_BT_HCIH4P is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+CONFIG_MTD_ONENAND_OTP=y
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_OMAP_STI=y
+CONFIG_OMAP_STI_CONSOLE=y
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=y
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+CONFIG_KEYBOARD_TSC2301=y
+CONFIG_KEYBOARD_LM8323=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+CONFIG_TOUCHSCREEN_TSC2005=y
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+CONFIG_TOUCHSCREEN_TSC2301=y
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+CONFIG_SENSORS_TSL2563=y
+CONFIG_LP5521=y
+CONFIG_MENELAUS=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+CONFIG_SPI_TSC2301=y
+CONFIG_SPI_TSC2301_AUDIO=y
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_TCM825X=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_AU0828 is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+CONFIG_VIDEO_OMAP2=y
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_RADIO_ADAPTERS=y
+CONFIG_RADIO_TEA5761=y
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_SG=y
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_LCDC_EXTERNAL=y
+# CONFIG_FB_OMAP_LCDC_HWA742 is not set
+CONFIG_FB_OMAP_LCDC_BLIZZARD=y
+CONFIG_FB_OMAP_MANUAL_UPDATE=y
+CONFIG_FB_OMAP_LCD_MIPID=y
+CONFIG_FB_OMAP_BOOTLOADER_INIT=y
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+CONFIG_SND_OMAP24XX_EAC=y
+
+#
+# SPI devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_PERSIST is not set
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_TUSB6010=y
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+# CONFIG_USB_INVENTRA_DMA is not set
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_TUSB_OMAP_DMA=y
+CONFIG_USB_MUSB_LOGLEVEL=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+CONFIG_USB_LIBUSUAL=y
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+CONFIG_LEDS_OMAP_PWM=y
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+CONFIG_CBUS=y
+CONFIG_CBUS_TAHVO=y
+CONFIG_CBUS_TAHVO_USER=y
+# CONFIG_CBUS_TAHVO_USB is not set
+CONFIG_CBUS_RETU=y
+CONFIG_CBUS_RETU_USER=y
+CONFIG_CBUS_RETU_POWERBUTTON=y
+CONFIG_CBUS_RETU_RTC=y
+CONFIG_CBUS_RETU_WDT=y
+CONFIG_CBUS_RETU_HEADSET=y
+CONFIG_OMAP_DSP=y
+# CONFIG_OMAP_DSP_MBCMD_VERBOSE is not set
+CONFIG_OMAP_DSP_FBEXPORT=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+# CONFIG_SECURITY_LOWMEM is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap2_evm_defconfig b/arch/arm/configs/omap2_evm_defconfig
new file mode 100644 (file)
index 0000000..61f0965
--- /dev/null
@@ -0,0 +1,1253 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc3-omap1
+# Wed Aug 20 21:20:25 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+CONFIG_ARCH_OMAP2=y
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+# CONFIG_OMAP_BOOT_REASON is not set
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+# CONFIG_OMAP_MUX_WARNINGS is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MPU_TIMER=y
+# CONFIG_OMAP_32K_TIMER is not set
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Core Type
+#
+CONFIG_ARCH_OMAP24XX=y
+# CONFIG_ARCH_OMAP2420 is not set
+CONFIG_ARCH_OMAP2430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_2430SDP is not set
+CONFIG_MACH_OMAP2EVM=y
+CONFIG_OMAP_TICK_GPTIMER=1
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_V6=y
+# CONFIG_CPU_32v6K is not set
+CONFIG_CPU_32v6=y
+CONFIG_CPU_ABRT_EV6=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V6=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V6=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/ram0 rw console=ttyS0,115200n8 initrd=0x80600000,8M ramdisk_size=8192"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+CONFIG_SMC911X=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_OMAP=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+# CONFIG_GPIOEXPANDER_OMAP is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL4030_USB is not set
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_MENELAUS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_OMAP24XX is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=m
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap3_beagle_defconfig b/arch/arm/configs/omap3_beagle_defconfig
new file mode 100644 (file)
index 0000000..7805995
--- /dev/null
@@ -0,0 +1,1334 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-omap1
+# Tue Aug  5 20:31:33 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_SMARTREFLEX is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+CONFIG_MACH_OMAP3_BEAGLE=y
+CONFIG_OMAP_TICK_GPTIMER=12
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C2_OMAP_BEAGLE is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=4
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap3_evm_defconfig b/arch/arm/configs/omap3_evm_defconfig
new file mode 100644 (file)
index 0000000..ebeaef3
--- /dev/null
@@ -0,0 +1,1393 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc7-omap1
+# Tue Aug 12 20:28:50 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+CONFIG_MACH_OMAP3EVM=y
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_OMAP_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+CONFIG_SMC911X=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
new file mode 100644 (file)
index 0000000..11c0cf7
--- /dev/null
@@ -0,0 +1,1419 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc7-omap1
+# Tue Jun 24 08:42:24 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_RESET_CLOCKS=y
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MCBSP is not set
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_LDP is not set
+CONFIG_MACH_OMAP_3430SDP=y
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_OMAP_HWECC=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_SMC911X is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_TWL4030=y
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+# CONFIG_TWL4030_MADC is not set
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=1
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+CONFIG_USB_TEST=y
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=y
+# CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+
+#
+# RTC interface
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+
+#
+# I2C RTC driver
+#
+CONFIG_RTC_DRV_TWL4030=y
+
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
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..4e03cfe
--- /dev/null
@@ -0,0 +1,1316 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-rc2-omap1
+# Wed Feb 20 17:05:42 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_ARCH_OMAP3 is not set
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_RESET_CLOCKS is not set
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_GPIO_SWITCH=y
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_STI is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP15XX is not set
+CONFIG_ARCH_OMAP16XX=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+# CONFIG_MACH_OMAP_H2 is not set
+CONFIG_MACH_OMAP_H3=y
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_NOKIA770 is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP CPU Speed
+#
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
+# CONFIG_OMAP_ARM_192MHZ is not set
+CONFIG_OMAP_ARM_168MHZ=y
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+# CONFIG_ATAGS_PROC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_LEGACY is not set
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+# CONFIG_IRLAN is not set
+# CONFIG_IRNET is not set
+# CONFIG_IRCOMM is not set
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+# CONFIG_IRDA_CACHE_LAST_LSAP is not set
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_KINGSUN_DONGLE is not set
+# CONFIG_KSDAZZLE_DONGLE is not set
+# CONFIG_KS959_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_MCS_FIR is not set
+# CONFIG_OMAP_IR is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_OMAP=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_OMAP_UWIRE=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_OMAP_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OMAP_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_OMAP=y
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_SEQIV is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/omap_ldp_defconfig b/arch/arm/configs/omap_ldp_defconfig
new file mode 100644 (file)
index 0000000..9a90975
--- /dev/null
@@ -0,0 +1,1196 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc2-omap1
+# Thu May 15 19:08:39 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+CONFIG_OMAP_DEBUG_SRAM_PATCH=y
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+CONFIG_OMAP_MUX=y
+CONFIG_OMAP_MUX_DEBUG=y
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_OMAP_SERIAL_WAKE=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+CONFIG_MACH_OMAP_LDP=y
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/nfs nfsroot=192.168.0.1:/home/user/buildroot ip=192.168.0.2:192.168.0.1:192.168.0.1:255.255.255.0:tgt:eth0:off rw console=ttyS2,115200n8"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+# CONFIG_NEON is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC2102 is not set
+# CONFIG_TOUCHSCREEN_TSC210X is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+CONFIG_TWL4030_MADC=y
+# CONFIG_TWL4030_USB is not set
+# CONFIG_TWL4030_PWRBUTTON is not set
+# CONFIG_TWL4030_POWEROFF is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_HAVE_GPIO_LIB=y
+
+#
+# GPIO Support
+#
+# CONFIG_DEBUG_GPIO is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MCP23S08 is not set
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+# CONFIG_W1_MASTER_DS1WM is not set
+CONFIG_HDQ_MASTER_OMAP=y
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+CONFIG_W1_SLAVE_BQ27000=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=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=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+# CONFIG_SND_OMAP24XX_EAC is not set
+
+#
+# SPI devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# ALSA SoC audio for Freescale SOCs
+#
+
+#
+# SoC Audio for the Texas Instruments OMAP
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_OTG=y
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+# CONFIG_USB_MUSB_HOST is not set
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_GADGET_MUSB_HDRC=y
+CONFIG_USB_MUSB_HDRC_HCD=y
+# CONFIG_MUSB_PIO_ONLY is not set
+CONFIG_USB_INVENTRA_DMA=y
+# CONFIG_USB_TI_CPPI_DMA is not set
+CONFIG_USB_MUSB_LOGLEVEL=0
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+CONFIG_USB_FILE_STORAGE_TEST=y
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_SPI is not set
+# CONFIG_NEW_LEDS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/overo_defconfig b/arch/arm/configs/overo_defconfig
new file mode 100644 (file)
index 0000000..24b5178
--- /dev/null
@@ -0,0 +1,1977 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5-omap1
+# Sat Sep  6 11:35:57 2008
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_SUPPORTS_AOUT=y
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
+# CONFIG_HAVE_IOREMAP_PROT is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_ARCH_TRACEHOOK is not set
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+CONFIG_HAVE_CLK=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_LSF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_MSM7X00A is not set
+
+#
+# TI OMAP Implementations
+#
+CONFIG_ARCH_OMAP_OTG=y
+# CONFIG_ARCH_OMAP1 is not set
+# CONFIG_ARCH_OMAP2 is not set
+CONFIG_ARCH_OMAP3=y
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
+# CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
+CONFIG_OMAP_SMARTREFLEX=y
+# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_BOOT_TAG=y
+CONFIG_OMAP_BOOT_REASON=y
+# CONFIG_OMAP_COMPONENT_VERSION is not set
+# CONFIG_OMAP_GPIO_SWITCH is not set
+# CONFIG_OMAP_MUX is not set
+CONFIG_OMAP_MCBSP=y
+# CONFIG_OMAP_MMU_FWK is not set
+# CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_DM_TIMER=y
+# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+CONFIG_OMAP_LL_DEBUG_UART3=y
+CONFIG_ARCH_OMAP34XX=y
+CONFIG_ARCH_OMAP3430=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_3430SDP is not set
+# CONFIG_MACH_OMAP3EVM is not set
+# CONFIG_MACH_OMAP3_BEAGLE is not set
+CONFIG_MACH_OVERO=y
+CONFIG_OMAP_TICK_GPTIMER=1
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_V7=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+CONFIG_CPU_PABRT_IFAR=y
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_HAS_ASID=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_ARM_THUMBEE=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_HAS_TLS_REG=y
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_PREEMPT is not set
+CONFIG_HZ=128
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=" debug "
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# 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=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_NEON=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=y
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=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=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIBTUSB is not set
+# CONFIG_BT_HCIBTSDIO is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIUART_LL is not set
+CONFIG_BT_HCIBCM203X=y
+CONFIG_BT_HCIBPA10X=y
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBRF6150 is not set
+# CONFIG_BT_HCIH4P is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+CONFIG_CFG80211=y
+CONFIG_NL80211=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=y
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_IEEE80211=y
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=y
+CONFIG_IEEE80211_CRYPT_CCMP=y
+CONFIG_IEEE80211_CRYPT_TKIP=y
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_OMAP2=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_93CX6=m
+# CONFIG_OMAP_STI is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_DELAY=m
+# CONFIG_DM_UEVENT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=y
+CONFIG_LIBERTAS_USB=y
+CONFIG_LIBERTAS_SDIO=y
+CONFIG_LIBERTAS_DEBUG=y
+CONFIG_USB_ZD1201=m
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+CONFIG_RTL8187=m
+# CONFIG_MAC80211_HWSIM is not set
+CONFIG_P54_COMMON=m
+CONFIG_P54_USB=m
+# CONFIG_IWLWIFI_LEDS is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_GPIO is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_OMAP=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_ISP1301_OMAP is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_TWL4030_CORE=y
+CONFIG_TWL4030_GPIO=y
+CONFIG_TWL4030_MADC=m
+CONFIG_TWL4030_USB=y
+CONFIG_TWL4030_USB_HS_ULPI=y
+CONFIG_TWL4030_PWRBUTTON=y
+CONFIG_TWL4030_POWEROFF=y
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_LP5521 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_OMAP24XX=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_TSC2101 is not set
+# CONFIG_SPI_TSC2102 is not set
+# CONFIG_SPI_TSC210X is not set
+# CONFIG_SPI_TSC2301 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_TSC210X is not set
+CONFIG_SENSORS_OMAP34XX=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_OMAP_WATCHDOG=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+CONFIG_MEDIA_ATTACH=y
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA827X=m
+CONFIG_MEDIA_TUNER_TDA18271=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_MT2060=m
+CONFIG_MEDIA_TUNER_MT2266=m
+CONFIG_MEDIA_TUNER_QT1010=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_MEDIA_TUNER_MXL5005S=m
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEO_V4L1=m
+CONFIG_VIDEO_TVEEPROM=m
+CONFIG_VIDEO_TUNER=m
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_MSP3400=m
+CONFIG_VIDEO_CS53L32A=m
+CONFIG_VIDEO_WM8775=m
+CONFIG_VIDEO_SAA711X=m
+CONFIG_VIDEO_CX25840=m
+CONFIG_VIDEO_CX2341X=m
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_AU0828 is not set
+CONFIG_V4L_USB_DRIVERS=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_GSPCA is not set
+CONFIG_VIDEO_PVRUSB2=m
+CONFIG_VIDEO_PVRUSB2_SYSFS=y
+CONFIG_VIDEO_PVRUSB2_DVB=y
+# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
+# CONFIG_VIDEO_EM28XX is not set
+CONFIG_VIDEO_USBVISION=m
+CONFIG_VIDEO_USBVIDEO=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_QUICKCAM_MESSENGER=m
+# CONFIG_USB_ET61X251 is not set
+CONFIG_VIDEO_OVCAMCHIP=m
+CONFIG_USB_W9968CF=m
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+# CONFIG_USB_ZC0301 is not set
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+CONFIG_USB_ZR364XX=m
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_RADIO_TEA5761 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_SI470X is not set
+CONFIG_DVB_CAPTURE_DRIVERS=y
+# CONFIG_TTPCI_EEPROM is not set
+
+#
+# Supported USB Adapters
+#
+CONFIG_DVB_USB=m
+# CONFIG_DVB_USB_DEBUG is not set
+CONFIG_DVB_USB_A800=m
+CONFIG_DVB_USB_DIBUSB_MB=m
+# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
+CONFIG_DVB_USB_DIBUSB_MC=m
+CONFIG_DVB_USB_DIB0700=m
+CONFIG_DVB_USB_UMT_010=m
+CONFIG_DVB_USB_CXUSB=m
+CONFIG_DVB_USB_M920X=m
+CONFIG_DVB_USB_GL861=m
+CONFIG_DVB_USB_AU6610=m
+CONFIG_DVB_USB_DIGITV=m
+CONFIG_DVB_USB_VP7045=m
+CONFIG_DVB_USB_VP702X=m
+CONFIG_DVB_USB_GP8PSK=m
+CONFIG_DVB_USB_NOVA_T_USB2=m
+CONFIG_DVB_USB_TTUSB2=m
+CONFIG_DVB_USB_DTT200U=m
+CONFIG_DVB_USB_OPERA1=m
+CONFIG_DVB_USB_AF9005=m
+CONFIG_DVB_USB_AF9005_REMOTE=m
+# CONFIG_DVB_USB_DW2102 is not set
+# CONFIG_DVB_USB_ANYSEE is not set
+CONFIG_DVB_TTUSB_BUDGET=m
+CONFIG_DVB_TTUSB_DEC=m
+CONFIG_DVB_CINERGYT2=m
+# CONFIG_DVB_CINERGYT2_TUNING is not set
+# CONFIG_DVB_SIANO_SMS1XXX is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+CONFIG_DVB_CX24110=m
+CONFIG_DVB_CX24123=m
+CONFIG_DVB_MT312=m
+CONFIG_DVB_S5H1420=m
+CONFIG_DVB_STV0299=m
+CONFIG_DVB_TDA8083=m
+CONFIG_DVB_TDA10086=m
+CONFIG_DVB_VES1X93=m
+CONFIG_DVB_TUNER_ITD1000=m
+CONFIG_DVB_TDA826X=m
+CONFIG_DVB_TUA6100=m
+
+#
+# DVB-T (terrestrial) frontends
+#
+CONFIG_DVB_SP8870=m
+CONFIG_DVB_SP887X=m
+CONFIG_DVB_CX22700=m
+CONFIG_DVB_CX22702=m
+# CONFIG_DVB_DRX397XD is not set
+CONFIG_DVB_L64781=m
+CONFIG_DVB_TDA1004X=m
+CONFIG_DVB_NXT6000=m
+CONFIG_DVB_MT352=m
+CONFIG_DVB_ZL10353=m
+CONFIG_DVB_DIB3000MB=m
+CONFIG_DVB_DIB3000MC=m
+CONFIG_DVB_DIB7000M=m
+CONFIG_DVB_DIB7000P=m
+CONFIG_DVB_TDA10048=m
+
+#
+# DVB-C (cable) frontends
+#
+CONFIG_DVB_VES1820=m
+CONFIG_DVB_TDA10021=m
+CONFIG_DVB_TDA10023=m
+CONFIG_DVB_STV0297=m
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+CONFIG_DVB_NXT200X=m
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+CONFIG_DVB_BCM3510=m
+CONFIG_DVB_LGDT330X=m
+CONFIG_DVB_S5H1409=m
+CONFIG_DVB_AU8522=m
+CONFIG_DVB_S5H1411=m
+
+#
+# Digital terrestrial only tuners/PLL
+#
+CONFIG_DVB_PLL=m
+CONFIG_DVB_TUNER_DIB0070=m
+
+#
+# SEC control devices for DVB-S
+#
+CONFIG_DVB_LNBP21=m
+# CONFIG_DVB_ISL6405 is not set
+CONFIG_DVB_ISL6421=m
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_031M3R is not set
+# CONFIG_FB_OMAP_048M3R is not set
+CONFIG_FB_OMAP_079M3R=y
+# CONFIG_FB_OMAP_092M9R is not set
+# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=8
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+CONFIG_DISPLAY_SUPPORT=y
+
+#
+# Display hardware drivers
+#
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_HWDEP=y
+CONFIG_SND_RAWMIDI=y
+CONFIG_SND_SEQUENCER=m
+# CONFIG_SND_SEQ_DUMMY 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_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+# CONFIG_SND_DEBUG_VERBOSE is not set
+# CONFIG_SND_PCM_XRUN_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+# CONFIG_SND_OMAP_AIC23 is not set
+# CONFIG_SND_OMAP_TSC2101 is not set
+# CONFIG_SND_SX1 is not set
+# CONFIG_SND_OMAP_TSC2102 is not set
+# CONFIG_SND_OMAP24XX_EAC is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_CAIAQ=m
+CONFIG_SND_USB_CAIAQ_INPUT=y
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_OVERO=y
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+CONFIG_HID_DEBUG=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=y
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_SOC=y
+
+#
+# OMAP 343x high speed USB support
+#
+CONFIG_USB_MUSB_HOST=y
+# CONFIG_USB_MUSB_PERIPHERAL is not set
+# CONFIG_USB_MUSB_OTG is not set
+CONFIG_USB_MUSB_HDRC_HCD=y
+CONFIG_MUSB_PIO_ONLY=y
+# CONFIG_USB_MUSB_DEBUG is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SIERRA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+# CONFIG_USB_BERRY_CHARGE is not set
+CONFIG_USB_LED=m
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SISUSBVGA_CON=y
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+CONFIG_SDIO_UART=y
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_OMAP_HS=y
+# CONFIG_MMC_SPI is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_OMAP_DEBUG is not set
+# CONFIG_LEDS_OMAP is not set
+# CONFIG_LEDS_OMAP_PWM is not set
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+CONFIG_RTC_DRV_TWL4030=y
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+
+#
+# Voltage and Current regulators
+#
+# CONFIG_REGULATOR is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_UIO is not set
+
+#
+# CBUS support
+#
+# CONFIG_CBUS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+CONFIG_QUOTA=y
+# CONFIG_QUOTA_NETLINK_INTERFACE is not set
+CONFIG_PRINT_QUOTA_WARNING=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+CONFIG_JFFS2_FS_POSIX_ACL=y
+CONFIG_JFFS2_FS_SECURITY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_AUTHENC is not set
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 8e21ef15bd743b9fb3b019bd7c9cc559c3c2ab61..acfac1a24bc0fefd1f0e0c4ac55d16624d5b7423 100644 (file)
@@ -292,6 +292,7 @@ static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define pmd_present(pmd)       (pmd_val(pmd))
 #define pmd_bad(pmd)           (pmd_val(pmd) & 2)
+#define pmd_table(pmd)         ((pmd_val(pmd) & PMD_TYPE_MASK) == PMD_TYPE_TABLE)
 
 #define copy_pmd(pmdpd,pmdps)          \
        do {                            \
index 7bbf105463f1adf8fd9cdaf68283cc87f3cb8c97..da786171d15cbb827c99a702aaced46cf1ef2a88 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 514af792a5980bd384dc158124df7e9036bdc926..704738eaeef4181e841d948c62cb3b1f2bfc4074 100644 (file)
                    : "cc");                                            \
                __val;                                                  \
        })
+#define read_extended_cpuid(op1,op2,op3,op4)           \
+       ({                                                              \
+               unsigned int __val;                                     \
+               asm("mrc p15," __stringify(op1) ",%0,c" __stringify(op2)",c" __stringify(op3)"," __stringify(op4)       \
+                   : "=r" (__val)                                      \
+                   :                                                   \
+                   : "cc");                                            \
+               __val;                                                  \
+       })
+
+#define write_extended_cpuid(op1,op2,op3,op4,v)                \
+       ({                                                              \
+               unsigned int __val = v;                                 \
+               asm("mcr p15," __stringify(op1) ",%0,c" __stringify(op2)",c" __stringify(op3)"," __stringify(op4)       \
+                   :                                                   \
+                   : "r" (__val)                                       \
+                   : "cc");                                            \
+       })
 #else
 extern unsigned int processor_id;
 #define read_cpuid(reg) (processor_id)
index 2ca7038b67a7bf105df3529491e0f9858220ca76..a69e034bafc010abb6eb6678a98fa163a84815e1 100644 (file)
@@ -255,6 +255,24 @@ static const char *proc_arch[] = {
        "?(17)",
 };
 
+static const char *v7_cache_policy[4] = {
+       "reserved",
+       "AVIVT",
+       "VIPT",
+       "PIPT",
+};
+
+static const char *v7_cache_type[8] = {
+       "none",
+       "instruction only",
+       "data only",
+       "separate instruction and data",
+       "unified",
+       "unknown type",
+       "unknown type",
+       "unknown type",
+};
+
 #define CACHE_TYPE(x)  (((x) >> 25) & 15)
 #define CACHE_S(x)     ((x) & (1 << 24))
 #define CACHE_DSIZE(x) (((x) >> 12) & 4095)    /* only if S=1 */
@@ -265,6 +283,22 @@ static const char *proc_arch[] = {
 #define CACHE_M(y)     ((y) & (1 << 2))
 #define CACHE_LINE(y)  ((y) & 3)
 
+#define CACHE_TYPE_V7(x)       (((x) >> 14) & 3)
+#define CACHE_UNIFIED(x)       ((((x) >> 27) & 7)+1)
+#define CACHE_COHERENT(x)      ((((x) >> 24) & 7)+1)
+
+#define CACHE_ID_LEVEL_MASK    7
+#define CACHE_ID_LEVEL_BITS    3
+
+#define CACHE_LINE_V7(v)       ((1 << (((v) & 7)+4)))
+#define CACHE_ASSOC_V7(v)      ((((v) >> 3) & ((1<<10)-1))+1)
+#define CACHE_SETS_V7(v)       ((((v) >> 13) & ((1<<15)-1))+1)
+#define CACHE_SIZE_V7(v)       (CACHE_LINE_V7(v)*CACHE_ASSOC_V7(v)*CACHE_SETS_V7(v))
+#define CACHE_WA_V7(v)         (((v) & (1<<28)) != 0)
+#define CACHE_RA_V7(v)         (((v) & (1<<29)) != 0)
+#define CACHE_WB_V7(v)         (((v) & (1<<30)) != 0)
+#define CACHE_WT_V7(v)         (((v) & (1<<31)) != 0)
+
 static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
 {
        unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
@@ -278,11 +312,57 @@ static inline void dump_cache(const char *prefix, int cpu, unsigned int cache)
                        CACHE_LINE(cache)));
 }
 
+static void dump_v7_cache(const char *type, int cpu, unsigned int level)
+{
+       unsigned int cachesize;
+                    
+       write_extended_cpuid(2,0,0,0,level);  /* Set the cache size selection register */
+       write_extended_cpuid(0,7,5,4,0);      /* Prefetch flush to wait for above */
+       cachesize = read_extended_cpuid(1,0,0,0);
+
+       printk("CPU%u: %s cache: %d bytes, associativity %d, %d byte lines, %d sets,\n      supports%s%s%s%s\n",
+              cpu, type,
+              CACHE_SIZE_V7(cachesize),CACHE_ASSOC_V7(cachesize),
+              CACHE_LINE_V7(cachesize),CACHE_SETS_V7(cachesize),
+              CACHE_WA_V7(cachesize) ? " WA" : "",
+              CACHE_RA_V7(cachesize) ? " RA" : "",
+              CACHE_WB_V7(cachesize) ? " WB" : "",
+              CACHE_WT_V7(cachesize) ? " WT" : "");
+}
+
 static void __init dump_cpu_info(int cpu)
 {
        unsigned int info = read_cpuid(CPUID_CACHETYPE);
 
-       if (info != processor_id) {
+       if (info != processor_id && (info & (1 << 31))) {
+               /* ARMv7 style of cache info register */
+               unsigned int id = read_extended_cpuid(1,0,0,1);
+               unsigned int level = 0;
+               printk("CPU%u: L1 I %s cache. Caches unified at level %u, coherent at level %u\n",
+                      cpu,
+                      v7_cache_policy[CACHE_TYPE_V7(info)],
+                      CACHE_UNIFIED(id),
+                      CACHE_COHERENT(id));
+
+               while (id & CACHE_ID_LEVEL_MASK) {
+                       printk("CPU%u: Level %u cache is %s\n",
+                              cpu, (level >> 1)+1, v7_cache_type[id & CACHE_ID_LEVEL_MASK]);
+
+                       if (id & 1) {
+                               /* Dump I at this level */
+                               dump_v7_cache("I", cpu, level | 1);
+                       }
+
+                       if (id & (4 | 2)) {
+                               /* Dump D or unified at this level */
+                               dump_v7_cache((id & 4) ? "unified" : "D", cpu, level);
+                       }
+
+                       /* Next level out */
+                       level += 2;
+                       id >>= CACHE_ID_LEVEL_BITS;
+               }
+       } else if (info != processor_id) {
                printk("CPU%u: D %s %s cache\n", cpu, cache_is_vivt() ? "VIVT" : "VIPT",
                       cache_types[CACHE_TYPE(info)]);
                if (CACHE_S(info)) {
@@ -917,6 +997,30 @@ c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
                            CACHE_LINE(cache)));
 }
 
+static void c_show_v7_cache(struct seq_file *m, const char *type, unsigned int levelselect)
+{
+       unsigned int cachesize;
+       unsigned int level = (levelselect >> 1) + 1;
+                    
+       write_extended_cpuid(2,0,0,0,levelselect);  /* Set the cache size selection register */
+       write_extended_cpuid(0,7,5,4,0);      /* Prefetch flush to wait for above */
+       cachesize = read_extended_cpuid(1,0,0,0);
+
+       seq_printf(m, "L%u %s size\t\t: %d bytes\n"
+                  "L%u %s assoc\t\t: %d\n"
+                  "L%u %s line length\t: %d\n"
+                  "L%u %s sets\t\t: %d\n"
+                  "L%u %s supports\t\t:%s%s%s%s\n",
+                  level, type, CACHE_SIZE_V7(cachesize),
+                  level, type, CACHE_ASSOC_V7(cachesize),
+                  level, type, CACHE_LINE_V7(cachesize),
+                  level, type, CACHE_SETS_V7(cachesize),
+                  level, type, CACHE_WA_V7(cachesize) ? " WA" : "",
+                  CACHE_RA_V7(cachesize) ? " RA" : "",
+                  CACHE_WB_V7(cachesize) ? " WB" : "",
+                  CACHE_WT_V7(cachesize) ? " WT" : "");
+}
+
 static int c_show(struct seq_file *m, void *v)
 {
        int i;
@@ -972,7 +1076,36 @@ static int c_show(struct seq_file *m, void *v)
 
        {
                unsigned int cache_info = read_cpuid(CPUID_CACHETYPE);
-               if (cache_info != processor_id) {
+               if (cache_info != processor_id && (cache_info & (1<<31))) {
+                       /* V7 style of cache info register */
+                       unsigned int id = read_extended_cpuid(1,0,0,1);
+                       unsigned int levelselect = 0;
+                       seq_printf(m, "L1 I cache\t:%s\n"
+                                  "Cache unification level\t: %u\n"
+                                  "Cache coherency level\t: %u\n",
+                                  v7_cache_policy[CACHE_TYPE_V7(cache_info)],
+                                  CACHE_UNIFIED(id),
+                                  CACHE_COHERENT(id));
+
+                       while (id & CACHE_ID_LEVEL_MASK) {
+                               seq_printf(m, "Level %u cache\t\t: %s\n",
+                                          (levelselect >> 1)+1, v7_cache_type[id & CACHE_ID_LEVEL_MASK]);
+
+                               if (id & 1) {
+                                       /* Dump I at this level */
+                                       c_show_v7_cache(m, "I", levelselect | 1);
+                               }
+
+                               if (id & (4 | 2)) {
+                                       /* Dump D or unified at this level */
+                                       c_show_v7_cache(m, (id & 4) ? "cache" : "D", levelselect);
+                               }
+
+                               /* Next level out */
+                               levelselect += 2;
+                               id >>= CACHE_ID_LEVEL_BITS;
+                       }
+               } else if (cache_info != processor_id) {
                        seq_printf(m, "Cache type\t: %s\n"
                                      "Cache clean\t: %s\n"
                                      "Cache lockdown\t: %s\n"
index 1bda8f5d754666550c24d3881cf0b7c59185848e..d8b7e1cbfc8eb4d92f1c6196707be25e901e4d93 100644 (file)
@@ -13,6 +13,12 @@ obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
 # Power Management
 obj-$(CONFIG_PM) += pm.o sleep.o
 
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK)     += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
+mailbox_mach-objs              := mailbox.o
+mmu_mach-objs                  := mmu.o
+
 led-y := leds.o
 
 # Specific board support
index ab9ee5820c489f935784fa1148764190ede72fdf..409fa56d0a87dce20d99f2075c6121a2815e26e3 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/platform_device.h>
+
+#include <linux/i2c/tps65010.h>
+
 #include <mach/mmc.h>
 #include <mach/gpio.h>
 
-#ifdef CONFIG_MMC_OMAP
-static int slot_cover_open;
-static struct device *mmc_device;
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
-static int h2_mmc_set_power(struct device *dev, int slot, int power_on,
+static int mmc_set_power(struct device *dev, int slot, int power_on,
                                int vdd)
 {
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
-               power_on ? "on" : "off", vdd);
-#endif
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
+       if (power_on)
+               gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 1);
+       else
+               gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 0);
 
        return 0;
 }
 
-static int h2_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+static int mmc_late_init(struct device *dev)
 {
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d bus_mode %s\n", slot + 1,
-               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
-#endif
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
+       int ret;
 
-       return 0;
-}
+       ret = gpio_request(H2_TPS_GPIO_MMC_PWR_EN, "MMC power");
+       if (ret < 0)
+               return ret;
 
-static int h2_mmc_get_cover_state(struct device *dev, int slot)
-{
-       BUG_ON(slot != 0);
-
-       return slot_cover_open;
-}
-
-void h2_mmc_slot_cover_handler(void *arg, int state)
-{
-       if (mmc_device == NULL)
-               return;
-
-       slot_cover_open = state;
-       omap_mmc_notify_cover_event(mmc_device, 0, state);
-}
-
-static int h2_mmc_late_init(struct device *dev)
-{
-       int ret = 0;
-
-       mmc_device = dev;
+       gpio_direction_output(H2_TPS_GPIO_MMC_PWR_EN, 0);
 
        return ret;
 }
 
-static void h2_mmc_cleanup(struct device *dev)
+static void mmc_shutdown(struct device *dev)
 {
+       gpio_free(H2_TPS_GPIO_MMC_PWR_EN);
 }
 
-static struct omap_mmc_platform_data h2_mmc_data = {
+/*
+ * H2 could use the following functions tested:
+ * - mmc_get_cover_state that uses OMAP_MPUIO(1)
+ * - mmc_get_wp that uses OMAP_MPUIO(3)
+ */
+static struct omap_mmc_platform_data mmc1_data = {
        .nr_slots                       = 1,
-       .switch_slot                    = NULL,
-       .init                           = h2_mmc_late_init,
-       .cleanup                        = h2_mmc_cleanup,
+       .init                           = mmc_late_init,
+       .shutdown                       = mmc_shutdown,
+       .dma_mask                       = 0xffffffff,
        .slots[0]       = {
-               .set_power              = h2_mmc_set_power,
-               .set_bus_mode           = h2_mmc_set_bus_mode,
-               .get_ro                 = NULL,
-               .get_cover_state        = h2_mmc_get_cover_state,
+               .set_power              = mmc_set_power,
                .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
                                          MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
 
+static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC];
+
 void __init h2_mmc_init(void)
 {
-       omap_set_mmc_info(1, &h2_mmc_data);
+       mmc_data[0] = &mmc1_data;
+       omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC);
 }
 
 #else
@@ -104,7 +82,4 @@ void __init h2_mmc_init(void)
 {
 }
 
-void h2_mmc_slot_cover_handler(void *arg, int state)
-{
-}
 #endif
index 3b65914b9141c79b3dab4d5936537a265dab7adc..2c12dfa8c09502b944bbb66b31e8dde34577a191 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
 #include <linux/i2c/tps65010.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2101.h>
+#include <linux/clk.h>
 
 #include <mach/hardware.h>
 #include <asm/gpio.h>
@@ -37,6 +42,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <mach/gpio.h>
 #include <mach/gpio-switch.h>
 #include <mach/mux.h>
 #include <mach/tc.h>
@@ -295,18 +301,36 @@ static struct platform_device h2_lcd_device = {
        .id             = -1,
 };
 
+struct {
+       struct clk      *mclk;
+       int             initialized;
+} h2_tsc2101;
+
+#define TSC2101_MUX_MCLK_ON    R10_1610_MCLK_ON
+#define TSC2101_MUX_MCLK_OFF   R10_1610_MCLK_OFF
+
+static void h2_lcd_dev_init(struct spi_device *tsc2101)
+{
+       /* The LCD is connected to the GPIO pins of the TSC2101, so
+        * we have to tie them here. We can also register the LCD driver
+        * first only here, where we know that the TSC driver is ready.
+        */
+
+       h2_lcd_device.dev.platform_data = tsc2101;
+       platform_device_register(&h2_lcd_device);
+}
+
 static struct omap_mcbsp_reg_cfg mcbsp_regs = {
        .spcr2 = FREE | FRST | GRST | XRST | XINTM(3),
        .spcr1 = RINTM(3) | RRST,
        .rcr2  = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) |
-                RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
+                       RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1),
        .rcr1  = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16),
        .xcr2  = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) |
-                XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
+                       XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG,
        .xcr1  = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16),
        .srgr1 = FWID(15),
        .srgr2 = GSYNC | CLKSP | FSGM | FPER(31),
-
        .pcr0  = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP,
        /*.pcr0 = CLKXP | CLKRP,*/        /* mcbsp: slave */
 };
@@ -314,12 +338,6 @@ static struct omap_mcbsp_reg_cfg mcbsp_regs = {
 static struct omap_alsa_codec_config alsa_config = {
        .name                   = "H2 TSC2101",
        .mcbsp_regs_alsa        = &mcbsp_regs,
-       .codec_configure_dev    = NULL, /* tsc2101_configure, */
-       .codec_set_samplerate   = NULL, /* tsc2101_set_samplerate, */
-       .codec_clock_setup      = NULL, /* tsc2101_clock_setup, */
-       .codec_clock_on         = NULL, /* tsc2101_clock_on, */
-       .codec_clock_off        = NULL, /* tsc2101_clock_off, */
-       .get_default_samplerate = NULL, /* tsc2101_get_default_samplerate, */
 };
 
 static struct platform_device h2_mcbsp1_device = {
@@ -330,14 +348,85 @@ static struct platform_device h2_mcbsp1_device = {
        },
 };
 
+static void h2_audio_dev_init(struct spi_device *tsc2101)
+{
+       h2_mcbsp1_device.dev.platform_data = tsc2101;
+       platform_device_register(&h2_mcbsp1_device);
+}
+
+static int h2_tsc2101_init(struct spi_device *spi)
+{
+       int r;
+
+       if (h2_tsc2101.initialized) {
+               printk(KERN_ERR "tsc2101: already initialized\n");
+               return -ENODEV;
+       }
+
+       /* Get the MCLK */
+       h2_tsc2101.mclk = clk_get(&spi->dev, "mclk");
+       if (IS_ERR(h2_tsc2101.mclk)) {
+               dev_err(&spi->dev, "unable to get the clock MCLK\n");
+               return PTR_ERR(h2_tsc2101.mclk);
+       }
+       if ((r = clk_set_rate(h2_tsc2101.mclk, 12000000)) < 0) {
+               dev_err(&spi->dev, "unable to set rate to the MCLK\n");
+               goto err;
+       }
+
+       omap_cfg_reg(TSC2101_MUX_MCLK_OFF);
+       omap_cfg_reg(N15_1610_UWIRE_CS1);
+
+       h2_lcd_dev_init(spi);
+       h2_audio_dev_init(spi);
+
+       return 0;
+err:
+       clk_put(h2_tsc2101.mclk);
+       return r;
+}
+
+static void h2_tsc2101_cleanup(struct spi_device *spi)
+{
+       clk_put(h2_tsc2101.mclk);
+       omap_cfg_reg(TSC2101_MUX_MCLK_OFF);
+}
+
+static void h2_tsc2101_enable_mclk(struct spi_device *spi)
+{
+       omap_cfg_reg(TSC2101_MUX_MCLK_ON);
+       clk_enable(h2_tsc2101.mclk);
+}
+
+static void h2_tsc2101_disable_mclk(struct spi_device *spi)
+{
+       clk_disable(h2_tsc2101.mclk);
+       omap_cfg_reg(R10_1610_MCLK_OFF);
+}
+
+static struct tsc2101_platform_data h2_tsc2101_platform_data = {
+       .init           = h2_tsc2101_init,
+       .cleanup        = h2_tsc2101_cleanup,
+       .enable_mclk    = h2_tsc2101_enable_mclk,
+       .disable_mclk   = h2_tsc2101_disable_mclk,
+};
+
+static struct spi_board_info h2_spi_board_info[] __initdata = {
+       [0] = {
+               .modalias       = "tsc2101",
+               .bus_num        = 2,
+               .chip_select    = 1,
+               .max_speed_hz   = 16000000,
+               .platform_data  = &h2_tsc2101_platform_data,
+       },
+};
+
 static struct platform_device *h2_devices[] __initdata = {
        &h2_nor_device,
        &h2_nand_device,
        &h2_smc91x_device,
        &h2_irda_device,
        &h2_kp_device,
-       &h2_lcd_device,
-       &h2_mcbsp1_device,
 };
 
 static void __init h2_init_smc91x(void)
@@ -348,10 +437,25 @@ static void __init h2_init_smc91x(void)
        }
 }
 
+static int tps_setup(struct i2c_client *client, void *context)
+{
+       tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V |
+                               TPS_LDO1_ENABLE | TPS_VLDO1_3_0V);
+
+       return 0;
+}
+
+static struct tps65010_board tps_board = {
+       .base           = H2_TPS_GPIO_BASE,
+       .outmask        = 0x0f,
+       .setup          = tps_setup,
+};
+
 static struct i2c_board_info __initdata h2_i2c_board_info[] = {
        {
                I2C_BOARD_INFO("tps65010", 0x48),
                .irq            = OMAP_GPIO_IRQ(58),
+               .platform_data  = &tps_board,
        }, {
                I2C_BOARD_INFO("isp1301_omap", 0x2d),
                .irq            = OMAP_GPIO_IRQ(2),
@@ -381,15 +485,6 @@ static struct omap_usb_config h2_usb_config __initdata = {
        .pins[1]        = 3,
 };
 
-static struct omap_mmc_config h2_mmc_config __initdata = {
-       .mmc[0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-       },
-};
-
-extern struct omap_mmc_platform_data h2_mmc_data;
-
 static struct omap_uart_config h2_uart_config __initdata = {
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
@@ -400,7 +495,6 @@ static struct omap_lcd_config h2_lcd_config __initdata = {
 
 static struct omap_board_config_kernel h2_config[] __initdata = {
        { OMAP_TAG_USB,         &h2_usb_config },
-       { OMAP_TAG_MMC,         &h2_mmc_config },
        { OMAP_TAG_UART,        &h2_uart_config },
        { OMAP_TAG_LCD,         &h2_lcd_config },
 };
@@ -448,6 +542,8 @@ static void __init h2_init(void)
 #endif
 
        platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
+       spi_register_board_info(h2_spi_board_info,
+                               ARRAY_SIZE(h2_spi_board_info));
        omap_board_config = h2_config;
        omap_board_config_size = ARRAY_SIZE(h2_config);
        omap_serial_init();
index 36085819098cbdd687665e42946fd0bfcb8a125c..fdfe793d56f2893e61d025ab63113846dc3ef51c 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/platform_device.h>
+
+#include <linux/i2c/tps65010.h>
+
 #include <mach/mmc.h>
 #include <mach/gpio.h>
 
-#ifdef CONFIG_MMC_OMAP
-static int slot_cover_open;
-static struct device *mmc_device;
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
-static int h3_mmc_set_power(struct device *dev, int slot, int power_on,
+static int mmc_set_power(struct device *dev, int slot, int power_on,
                                int vdd)
 {
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
-               power_on ? "on" : "off", vdd);
-#endif
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
+       if (power_on)
+               gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 1);
+       else
+               gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 0);
 
        return 0;
 }
 
-static int h3_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
-{
-       int ret = 0;
-
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d bus_mode %s\n", slot + 1,
-               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
-#endif
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
-
-       /* Treated on upper level */
-
-       return bus_mode;
-}
-
-static int h3_mmc_get_cover_state(struct device *dev, int slot)
-{
-       BUG_ON(slot != 0);
-
-       return slot_cover_open;
-}
-
-void h3_mmc_slot_cover_handler(void *arg, int state)
-{
-       if (mmc_device == NULL)
-               return;
-
-       slot_cover_open = state;
-       omap_mmc_notify_cover_event(mmc_device, 0, state);
-}
-
-static int h3_mmc_late_init(struct device *dev)
-{
-       int ret = 0;
-
-       mmc_device = dev;
-
-       return ret;
-}
-
-static void h3_mmc_cleanup(struct device *dev)
-{
-}
-
-static struct omap_mmc_platform_data h3_mmc_data = {
+/*
+ * H3 could use the following functions tested:
+ * - mmc_get_cover_state that uses OMAP_MPUIO(1)
+ * - mmc_get_wp that maybe uses OMAP_MPUIO(3)
+ */
+static struct omap_mmc_platform_data mmc1_data = {
        .nr_slots                       = 1,
-       .switch_slot                    = NULL,
-       .init                           = h3_mmc_late_init,
-       .cleanup                        = h3_mmc_cleanup,
+       .dma_mask                       = 0xffffffff,
        .slots[0]       = {
-               .set_power              = h3_mmc_set_power,
-               .set_bus_mode           = h3_mmc_set_bus_mode,
-               .get_ro                 = NULL,
-               .get_cover_state        = h3_mmc_get_cover_state,
+               .set_power              = mmc_set_power,
                .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
                                          MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
 
+static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC];
+
 void __init h3_mmc_init(void)
 {
-       omap_set_mmc_info(1, &h3_mmc_data);
+       int ret;
+
+       ret = gpio_request(H3_TPS_GPIO_MMC_PWR_EN, "MMC power");
+       if (ret < 0)
+               return;
+       gpio_direction_output(H3_TPS_GPIO_MMC_PWR_EN, 0);
+
+       mmc_data[0] = &mmc1_data;
+       omap1_init_mmc(mmc_data, OMAP16XX_NR_MMC);
 }
 
 #else
@@ -108,7 +69,4 @@ void __init h3_mmc_init(void)
 {
 }
 
-void h3_mmc_slot_cover_handler(void *arg, int state)
-{
-}
 #endif
index 2ced6d9984d27802844a448aa37720f54889d62a..6706cad78b9b876c8129df68b3b9d00a42a92efe 100644 (file)
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/input.h>
-#include <linux/spi/spi.h>
 #include <linux/i2c/tps65010.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <media/v4l2-int-device.h>
+
+#include <mach/gpio.h>
+#include <mach/gpio-switch.h>
 #include <mach/gpioexpander.h>
 #include <mach/irqs.h>
 #include <mach/mux.h>
@@ -52,6 +58,8 @@
 #include <mach/mcbsp.h>
 #include <mach/omap-alsa.h>
 
+#include <../drivers/media/video/ov9640.h>
+
 #define H3_TS_GPIO     48
 
 static int h3_keymap[] = {
@@ -376,6 +384,12 @@ static struct platform_device h3_lcd_device = {
        .id             = -1,
 };
 
+static struct tsc210x_config tsc_platform_data = {
+       .use_internal           = 1,
+       .monitor                = TSC_VBAT | TSC_TEMP,
+       .mclk                   = "mclk",
+};
+
 static struct spi_board_info h3_spi_board_info[] __initdata = {
        [0] = {
                .modalias       = "tsc2101",
@@ -383,7 +397,7 @@ static struct spi_board_info h3_spi_board_info[] __initdata = {
                .chip_select    = 0,
                .irq            = OMAP_GPIO_IRQ(H3_TS_GPIO),
                .max_speed_hz   = 16000000,
-               /* .platform_data       = &tsc_platform_data, */
+               .platform_data  = &tsc_platform_data,
        },
 };
 
@@ -447,15 +461,6 @@ static struct omap_usb_config h3_usb_config __initdata = {
        .pins[1]        = 3,
 };
 
-static struct omap_mmc_config h3_mmc_config __initdata = {
-       .mmc[0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-       },
-};
-
-extern struct omap_mmc_platform_data h3_mmc_data;
-
 static struct omap_uart_config h3_uart_config __initdata = {
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
@@ -466,37 +471,128 @@ static struct omap_lcd_config h3_lcd_config __initdata = {
 
 static struct omap_board_config_kernel h3_config[] __initdata = {
        { OMAP_TAG_USB,         &h3_usb_config },
-       { OMAP_TAG_MMC,         &h3_mmc_config },
        { OMAP_TAG_UART,        &h3_uart_config },
        { OMAP_TAG_LCD,         &h3_lcd_config },
 };
 
+#define H3_NAND_RB_GPIO_PIN    10
+
+static int nand_dev_ready(struct omap_nand_platform_data *data)
+{
+       return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
+}
+
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+/*
+ * Common OV9640 register initialization for all image sizes, pixel formats,
+ * and frame rates
+ */
+const static struct ov9640_reg ov9640_common[] = {
+
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x88 }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x58 }, { 0x02, 0x24 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0xcA }, /* COM5, COM6, COM9 */
+       { 0x16, 0x02 }, { 0x1B, 0x01 }, { 0x24, 0x70 }, /* ?, PSHFT, AEW */
+       { 0x25, 0x68 }, { 0x26, 0xD3 }, { 0x27, 0x90 }, /* AEB, VPT, BBIAS */
+       { 0x2A, 0x00 }, { 0x2B, 0x00 }, { 0x32, 0x24 }, /* EXHCH, EXHCL, HREF */
+       { 0x33, 0x02 }, { 0x37, 0x02 }, { 0x38, 0x13 }, /* CHLF, ADC, ACOM */
+       { 0x39, 0xF0 }, { 0x3A, 0x00 }, { 0x3B, 0x01 }, /* OFON, TSLB, COM11 */
+       { 0x3D, 0x90 }, { 0x3E, 0x02 }, { 0x3F, 0xF2 }, /* COM13, COM14, EDGE */
+       { 0x41, 0x02 }, { 0x42, 0xC8 },         /* COM16, COM17 */
+       { 0x43, 0xF0 }, { 0x44, 0x10 }, { 0x45, 0x6C }, /* ?, ?, ? */
+       { 0x46, 0x6C }, { 0x47, 0x44 }, { 0x48, 0x44 }, /* ?, ?, ? */
+       { 0x49, 0x03 }, { 0x59, 0x49 }, { 0x5A, 0x94 }, /* ?, ?, ? */
+       { 0x5B, 0x46 }, { 0x5C, 0x84 }, { 0x5D, 0x5C }, /* ?, ?, ? */
+       { 0x5E, 0x08 }, { 0x5F, 0x00 }, { 0x60, 0x14 }, /* ?, ?, ? */
+       { 0x61, 0xCE },                                 /* ? */
+       { 0x62, 0x70 }, { 0x63, 0x00 }, { 0x64, 0x04 }, /* LCC1, LCC2, LCC3 */
+       { 0x65, 0x00 }, { 0x66, 0x00 },                 /* LCC4, LCC5 */
+       { 0x69, 0x00 }, { 0x6A, 0x3E }, { 0x6B, 0x3F }, /* HV, MBD, DBLV */
+       { 0x6C, 0x40 }, { 0x6D, 0x30 }, { 0x6E, 0x4B }, /* GSP1, GSP2, GSP3 */
+       { 0x6F, 0x60 }, { 0x70, 0x70 }, { 0x71, 0x70 }, /* GSP4, GSP5, GSP6 */
+       { 0x72, 0x70 }, { 0x73, 0x70 }, { 0x74, 0x60 }, /* GSP7, GSP8, GSP9 */
+       { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, /* GSP10,GSP11,GSP12 */
+       { 0x78, 0x3A }, { 0x79, 0x2E }, { 0x7A, 0x28 }, /* GSP13,GSP14,GSP15 */
+       { 0x7B, 0x22 }, { 0x7C, 0x04 }, { 0x7D, 0x07 }, /* GSP16,GST1, GST2 */
+       { 0x7E, 0x10 }, { 0x7F, 0x28 }, { 0x80, 0x36 }, /* GST3, GST4, GST5 */
+       { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, /* GST6, GST7, GST8 */
+       { 0x84, 0x6C }, { 0x85, 0x78 }, { 0x86, 0x8C }, /* GST9, GST10,GST11 */
+       { 0x87, 0x9E }, { 0x88, 0xBB }, { 0x89, 0xD2 }, /* GST12,GST13,GST14 */
+       { 0x8A, 0xE6 }, { 0x13, 0xaF }, { 0x15, 0x02 }, /* GST15, COM8 */
+       { 0x22, 0x8a }, /* GROS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+static int ov9640_sensor_power_set(int power)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       err = read_gpio_expa(&expa, 0x27);
+       if (err) {
+               printk(KERN_ERR "Error reading GPIO EXPA\n");
+               return err;
+       }
+       /* Clear GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up/down sensor */
+       if (power)
+               expa |= 0x08;
+       else
+               expa &= ~0x08;
+
+       err = write_gpio_expa(expa, 0x27);
+       if (err) {
+               printk(KERN_ERR "Error writing to GPIO EXPA\n");
+               return err;
+       }
+
+       return err;
+}
+
+static struct v4l2_ifparm ifparm = {
+       .if_type = V4L2_IF_TYPE_BT656,
+       .u = {
+               .bt656 = {
+                        .frame_start_on_rising_vs = 1,
+                        .nobt_vs_inv = 1,
+                        .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+                        .clock_min = OV9640_XCLK_MIN,
+                        .clock_max = OV9640_XCLK_MAX,
+                },
+       },
+};
+
+static int ov9640_ifparm(struct v4l2_ifparm *p)
+{
+       *p = ifparm;
+
+       return 0;
+}
+
+static struct ov9640_platform_data h3_ov9640_platform_data = {
+       .power_set      = ov9640_sensor_power_set,
+       .default_regs   = ov9640_common,
+       .ifparm         = ov9640_ifparm,
+};
+#endif
+
 static struct i2c_board_info __initdata h3_i2c_board_info[] = {
        {
                I2C_BOARD_INFO("tps65013", 0x48),
                /* .irq         = OMAP_GPIO_IRQ(??), */
        },
-};
-
-static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
        {
-               .name                   = "mmc_slot",
-               .gpio                   = OMAP_MPUIO(1),
-               .type                   = OMAP_GPIO_SWITCH_TYPE_COVER,
-               .debounce_rising        = 100,
-               .debounce_falling       = 0,
-               .notify                 = h3_mmc_slot_cover_handler,
-               .notify_data            = NULL,
+               I2C_BOARD_INFO("ov9640", 0x30),
+               .platform_data = &h3_ov9640_platform_data,
+       },
+#endif
+       {
+               I2C_BOARD_INFO("isp1301_omap", 0x2d),
+               .irq            = OMAP_GPIO_IRQ(14),
        },
 };
 
-#define H3_NAND_RB_GPIO_PIN    10
-
-static int nand_dev_ready(struct omap_nand_platform_data *data)
-{
-       return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN);
-}
-
 static void __init h3_init(void)
 {
        /* Here we assume the NOR boot config:  NOR on CS3 (possibly swapped
@@ -519,6 +615,12 @@ static void __init h3_init(void)
        /* GPIO10 pullup/down register, Enable pullup on GPIO10 */
        omap_cfg_reg(V2_1710_GPIO10);
 
+       /* TSC2101 */
+       omap_cfg_reg(W19_1610_GPIO48);
+       gpio_request(H3_TS_GPIO, "tsc_irq");
+       gpio_direction_input(H3_TS_GPIO);
+       omap_cfg_reg(N14_1610_UWIRE_CS0);
+
        platform_add_devices(devices, ARRAY_SIZE(devices));
        spi_register_board_info(h3_spi_board_info,
                                ARRAY_SIZE(h3_spi_board_info));
index cbc11be5cd2a9ebcbc1fc43f82308f17c969076c..7a97f6b5357a62329a3244a36970fae27d2fc024 100644 (file)
@@ -39,6 +39,7 @@
 #include <mach/common.h>
 #include <mach/mcbsp.h>
 #include <mach/omap-alsa.h>
+#include <mach/mmc.h>
 
 static int innovator_keymap[] = {
        KEY(0, 0, KEY_F1),
@@ -360,16 +361,49 @@ static struct omap_lcd_config innovator1610_lcd_config __initdata = {
 };
 #endif
 
-static struct omap_mmc_config innovator_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-               .wp_pin         = OMAP_MPUIO(3),
-               .power_pin      = -1,   /* FPGA F3 UIO42 */
-               .switch_pin     = -1,   /* FPGA F4 UIO43 */
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+static int mmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       if (power_on)
+               fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3),
+                               OMAP1510_FPGA_POWER);
+       else
+               fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3),
+                               OMAP1510_FPGA_POWER);
+
+       return 0;
+}
+
+/*
+ * Innovator could use the following functions tested:
+ * - mmc_get_wp that uses OMAP_MPUIO(3)
+ * - mmc_get_cover_state that uses FPGA F4 UIO43
+ */
+static struct omap_mmc_platform_data mmc1_data = {
+       .nr_slots                       = 1,
+       .slots[0]       = {
+               .set_power              = mmc_set_power,
+               .wire4                  = 1,
+               .name                   = "mmcblk",
        },
 };
 
+static struct omap_mmc_platform_data *mmc_data[OMAP16XX_NR_MMC];
+
+void __init innovator_mmc_init(void)
+{
+       mmc_data[0] = &mmc1_data;
+       omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC);
+}
+
+#else
+static inline void innovator_mmc_init(void)
+{
+}
+#endif
+
 static struct omap_uart_config innovator_uart_config __initdata = {
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
@@ -377,7 +411,6 @@ static struct omap_uart_config innovator_uart_config __initdata = {
 static struct omap_board_config_kernel innovator_config[] = {
        { OMAP_TAG_USB,         NULL },
        { OMAP_TAG_LCD,         NULL },
-       { OMAP_TAG_MMC,         &innovator_mmc_config },
        { OMAP_TAG_UART,        &innovator_uart_config },
 };
 
@@ -412,6 +445,7 @@ static void __init innovator_init(void)
        omap_board_config_size = ARRAY_SIZE(innovator_config);
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
+       innovator_mmc_init();
 }
 
 static void __init innovator_map_io(void)
index 38d9783ac6d6fe420972df38f2b3fb4993ec8440..7b28f4da214a63a907e637cf5888018698a3b8f5 100644 (file)
@@ -34,7 +34,9 @@
 #include <mach/dsp_common.h>
 #include <mach/aic23.h>
 #include <mach/omapfb.h>
+#include <mach/hwa742.h>
 #include <mach/lcd_mipid.h>
+#include <mach/mmc.h>
 
 #define ADS7846_PENDOWN_GPIO   15
 
@@ -162,6 +164,47 @@ static struct spi_board_info nokia770_spi_board_info[] __initdata = {
        },
 };
 
+static struct {
+       struct clk *sys_ck;
+} hwa742;
+
+static int hwa742_get_clocks(void)
+{
+       hwa742.sys_ck = clk_get(NULL, "bclk");
+       if (IS_ERR(hwa742.sys_ck)) {
+               printk(KERN_ERR "can't get HWA742 clock\n");
+               return PTR_ERR(hwa742.sys_ck);
+       }
+       return 0;
+}
+
+static unsigned long hwa742_get_clock_rate(struct device *dev)
+{
+       return clk_get_rate(hwa742.sys_ck);
+}
+
+static void hwa742_power_up(struct device *dev)
+{
+       clk_enable(hwa742.sys_ck);
+}
+
+static void hwa742_power_down(struct device *dev)
+{
+       clk_disable(hwa742.sys_ck);
+}
+
+static struct hwa742_platform_data nokia770_hwa742_platform_data = {
+       .get_clock_rate = hwa742_get_clock_rate,
+       .power_up       = hwa742_power_up,
+       .power_down     = hwa742_power_down,
+       .te_connected   = 1,
+};
+
+static void hwa742_dev_init(void)
+{
+       hwa742_get_clocks();
+       omapfb_set_ctrl_platform_data(&nokia770_hwa742_platform_data);
+}
 
 /* assume no Mini-AB port */
 
@@ -173,26 +216,68 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
        .pins[0]        = 6,
 };
 
-static struct omap_mmc_config nokia770_mmc_config __initdata = {
-       .mmc[0] = {
-               .enabled        = 0,
-               .wire4          = 0,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
-       },
-       .mmc[1] = {
-               .enabled        = 0,
-               .wire4          = 0,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+#define NOKIA770_GPIO_MMC_POWER                41
+#define NOKIA770_GPIO_MMC_SWITCH       23
+
+static int nokia770_mmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       if (power_on)
+               gpio_set_value(NOKIA770_GPIO_MMC_POWER, 1);
+       else
+               gpio_set_value(NOKIA770_GPIO_MMC_POWER, 0);
+
+       return 0;
+}
+
+static int nokia770_mmc_get_cover_state(struct device *dev, int slot)
+{
+       return gpio_get_value(NOKIA770_GPIO_MMC_SWITCH);
+}
+
+static struct omap_mmc_platform_data nokia770_mmc2_data = {
+       .nr_slots                       = 1,
+       .dma_mask                       = 0xffffffff,
+       .slots[0]       = {
+               .set_power              = nokia770_mmc_set_power,
+               .get_cover_state        = nokia770_mmc_get_cover_state,
+               .name                   = "mmcblk",
        },
 };
 
+static struct omap_mmc_platform_data *nokia770_mmc_data[OMAP16XX_NR_MMC];
+
+static void __init nokia770_mmc_init(void)
+{
+       int ret;
+
+       ret = gpio_request(NOKIA770_GPIO_MMC_POWER, "MMC power");
+       if (ret < 0)
+               return;
+       gpio_direction_output(NOKIA770_GPIO_MMC_POWER, 0);
+
+       ret = gpio_request(NOKIA770_GPIO_MMC_SWITCH, "MMC cover");
+       if (ret < 0) {
+               gpio_free(NOKIA770_GPIO_MMC_POWER);
+               return;
+       }
+       gpio_direction_input(NOKIA770_GPIO_MMC_SWITCH);
+
+       /* Only the second MMC controller is used */
+       nokia770_mmc_data[1] = &nokia770_mmc2_data;
+       omap1_init_mmc(nokia770_mmc_data, OMAP16XX_NR_MMC);
+}
+
+#else
+static inline void nokia770_mmc_init(void)
+{
+}
+#endif
+
 static struct omap_board_config_kernel nokia770_config[] __initdata = {
        { OMAP_TAG_USB,         NULL },
-       { OMAP_TAG_MMC,         &nokia770_mmc_config },
 };
 
 #if    defined(CONFIG_OMAP_DSP)
@@ -333,8 +418,10 @@ static void __init omap_nokia770_init(void)
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
        omap_dsp_init();
+       hwa742_dev_init();
        ads7846_dev_init();
        mipid_dev_init();
+       nokia770_mmc_init();
 }
 
 static void __init omap_nokia770_map_io(void)
index b58043644a6f55681ba5c66cb1d3a47f03687116..ee49e2ccf1f99d833cbbb4ab08580a00c8412ead 100644 (file)
@@ -44,6 +44,7 @@
 #include <mach/common.h>
 #include <mach/mcbsp.h>
 #include <mach/omap-alsa.h>
+#include <mach/gpio-switch.h>
 
 static void __init omap_palmte_init_irq(void)
 {
@@ -195,15 +196,6 @@ static struct omap_usb_config palmte_usb_config __initdata = {
        .pins[0]        = 2,
 };
 
-static struct omap_mmc_config palmte_mmc_config __initdata = {
-       .mmc[0]         = {
-               .enabled        = 1,
-               .wp_pin         = PALMTE_MMC_WP_GPIO,
-               .power_pin      = PALMTE_MMC_POWER_GPIO,
-               .switch_pin     = PALMTE_MMC_SWITCH_GPIO,
-       },
-};
-
 static struct omap_lcd_config palmte_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
@@ -316,7 +308,6 @@ static void palmte_get_power_status(struct apm_power_info *info, int *battery)
 
 static struct omap_board_config_kernel palmte_config[] __initdata = {
        { OMAP_TAG_USB,         &palmte_usb_config },
-       { OMAP_TAG_MMC,         &palmte_mmc_config },
        { OMAP_TAG_LCD,         &palmte_lcd_config },
        { OMAP_TAG_UART,        &palmte_uart_config },
 };
@@ -344,6 +335,37 @@ static void palmte_headphones_detect(void *data, int state)
        }
 }
 
+static struct omap_gpio_switch palmte_switches[] __initdata = {
+       /* Speaker-enable pin is an output */
+       {
+               .name   = "speaker-enable",
+               .gpio   = PALMTE_SPEAKER_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_ACTIVITY,
+               .flags  = OMAP_GPIO_SWITCH_FLAG_OUTPUT |
+                       OMAP_GPIO_SWITCH_FLAG_INVERTED,
+       },
+       /* Indicates whether power is from DC-IN or battery */
+       {
+               .name   = "dc-in",
+               .gpio   = PALMTE_DC_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+               .flags  = OMAP_GPIO_SWITCH_FLAG_INVERTED,
+       },
+       /* Indicates whether a USB host is on the other end of the cable */
+       {
+               .name   = "usb",
+               .gpio   = PALMTE_USBDETECT_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+       },
+       /* High when headphones jack is plugged in */
+       {
+               .name   = "headphones",
+               .gpio   = PALMTE_HEADPHONES_GPIO,
+               .type   = OMAP_GPIO_SWITCH_TYPE_CONNECTION,
+               .notify = palmte_headphones_detect,
+       },
+};
+
 static void __init palmte_misc_gpio_setup(void)
 {
        /* Set TSC2102 PINTDAV pin as input (used by TSC2102 driver) */
@@ -369,6 +391,10 @@ static void __init omap_palmte_init(void)
        platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
 
        spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
+
+       omap_register_gpio_switches(palmte_switches,
+                       ARRAY_SIZE(palmte_switches));
+
        palmte_misc_gpio_setup();
        omap_serial_init();
        omap_register_i2c_bus(1, 100, NULL, 0);
index e719294250b1f5dedf0bbec0a486ee855caf536d..e8116c5125909a5e5583232818fa617a0b866158 100644 (file)
@@ -267,16 +267,6 @@ static struct omap_usb_config palmz71_usb_config __initdata = {
        .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",
 };
@@ -287,7 +277,6 @@ static struct omap_uart_config palmz71_uart_config __initdata = {
 
 static struct omap_board_config_kernel palmz71_config[] __initdata = {
        {OMAP_TAG_USB,  &palmz71_usb_config},
-       {OMAP_TAG_MMC,  &palmz71_mmc_config},
        {OMAP_TAG_LCD,  &palmz71_lcd_config},
        {OMAP_TAG_UART, &palmz71_uart_config},
 };
index 0be4ebaa2842a120e2be29e96ce8906ec32fb105..66a4d7d5255d2f767c18cf370b074e4472ff451c 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/platform_device.h>
+
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/gpio.h>
 
-#ifdef CONFIG_MMC_OMAP
-static int slot_cover_open;
-static struct device *mmc_device;
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
 
-static int sx1_mmc_set_power(struct device *dev, int slot, int power_on,
+static int mmc_set_power(struct device *dev, int slot, int power_on,
                                int vdd)
 {
        int err;
        u8 dat = 0;
 
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
-               power_on ? "on" : "off", vdd);
-#endif
-
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
-
        err = sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
        if (err < 0)
                return err;
@@ -48,68 +38,23 @@ static int sx1_mmc_set_power(struct device *dev, int slot, int power_on,
        return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
 }
 
-static int sx1_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
-{
-#ifdef CONFIG_MMC_DEBUG
-       dev_dbg(dev, "Set slot %d bus_mode %s\n", slot + 1,
-               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
-#endif
-       if (slot != 0) {
-               dev_err(dev, "No such slot %d\n", slot + 1);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int sx1_mmc_get_cover_state(struct device *dev, int slot)
-{
-       BUG_ON(slot != 0);
-
-       return slot_cover_open;
-}
-
-void sx1_mmc_slot_cover_handler(void *arg, int state)
-{
-       if (mmc_device == NULL)
-               return;
-
-       slot_cover_open = state;
-       omap_mmc_notify_cover_event(mmc_device, 0, state);
-}
-
-static int sx1_mmc_late_init(struct device *dev)
-{
-       int ret = 0;
-
-       mmc_device = dev;
-
-       return ret;
-}
-
-static void sx1_mmc_cleanup(struct device *dev)
-{
-}
-
-static struct omap_mmc_platform_data sx1_mmc_data = {
+/* Cover switch is at OMAP_MPUIO(3) */
+static struct omap_mmc_platform_data mmc1_data = {
        .nr_slots                       = 1,
-       .switch_slot                    = NULL,
-       .init                           = sx1_mmc_late_init,
-       .cleanup                        = sx1_mmc_cleanup,
        .slots[0]       = {
-               .set_power              = sx1_mmc_set_power,
-               .set_bus_mode           = sx1_mmc_set_bus_mode,
-               .get_ro                 = NULL,
-               .get_cover_state        = sx1_mmc_get_cover_state,
+               .set_power              = mmc_set_power,
                .ocr_mask               = MMC_VDD_28_29 | MMC_VDD_30_31 |
                                          MMC_VDD_32_33 | MMC_VDD_33_34,
                .name                   = "mmcblk",
        },
 };
 
+static struct omap_mmc_platform_data *mmc_data[OMAP15XX_NR_MMC];
+
 void __init sx1_mmc_init(void)
 {
-       omap_set_mmc_info(1, &sx1_mmc_data);
+       mmc_data[0] = &mmc1_data;
+       omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC);
 }
 
 #else
@@ -118,7 +63,4 @@ void __init sx1_mmc_init(void)
 {
 }
 
-void sx1_mmc_slot_cover_handler(void *arg, int state)
-{
-}
 #endif
index 130bcc6fd082b4a7fa5745e3bb0d3c27b059f68b..e9ba5dc5074a0bdb2beaece26931e43ff3f57d9c 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/mach/map.h>
 
 #include <mach/gpio.h>
+#include <mach/gpio-switch.h>
 #include <mach/mux.h>
 #include <mach/irda.h>
 #include <mach/usb.h>
@@ -378,15 +379,6 @@ static struct omap_usb_config sx1_usb_config __initdata = {
        .pins[2]        = 0,
 };
 
-/*----------- MMC -------------------------*/
-
-static struct omap_mmc_config sx1_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 1,
-               .wire4          = 0,
-       },
-};
-
 /*----------- LCD -------------------------*/
 
 static struct platform_device sx1_lcd_device = {
@@ -414,7 +406,6 @@ static struct omap_uart_config sx1_uart_config __initdata = {
 
 static struct omap_board_config_kernel sx1_config[] __initdata = {
        { OMAP_TAG_USB, &sx1_usb_config },
-       { OMAP_TAG_MMC, &sx1_mmc_config },
        { OMAP_TAG_LCD, &sx1_lcd_config },
        { OMAP_TAG_UART,        &sx1_uart_config },
 };
@@ -443,7 +434,6 @@ static void __init omap_sx1_init(void)
        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)
index 213b48787102bf461ae30134907cd2fab0089127..069ca8d48aa33cb4bc8e8fb37716a84fa292aa1f 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/notifier.h>
@@ -139,21 +140,12 @@ static struct omap_usb_config voiceblue_usb_config __initdata = {
        .pins[2]        = 6,
 };
 
-static struct omap_mmc_config voiceblue_mmc_config __initdata = {
-       .mmc[0] = {
-               .enabled        = 1,
-               .power_pin      = 2,
-               .switch_pin     = -1,
-       },
-};
-
 static struct omap_uart_config voiceblue_uart_config __initdata = {
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
 static struct omap_board_config_kernel voiceblue_config[] = {
        { OMAP_TAG_USB,  &voiceblue_usb_config },
-       { OMAP_TAG_MMC,  &voiceblue_mmc_config },
        { OMAP_TAG_UART, &voiceblue_uart_config },
 };
 
index 5965cf09f8c4ab57b875fec102752c1779cad1b1..799867c1faf6093540031d79fd2abb9730856dff 100644 (file)
@@ -41,7 +41,7 @@ static void omap1_watchdog_recalc(struct clk * clk)
 
 static void omap1_uart_recalc(struct clk * clk)
 {
-       unsigned int val = omap_readl(clk->enable_reg);
+       unsigned int val = __raw_readl(clk->enable_reg);
        if (val & clk->enable_bit)
                clk->rate = 48000000;
        else
@@ -201,7 +201,7 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        parent = clk->parent;
-       if (unlikely(parent == 0))
+       if (unlikely(parent == NULL))
                return -EIO;
 
        realrate = parent->rate;
@@ -372,14 +372,14 @@ static int omap1_set_uart_rate(struct clk * clk, unsigned long rate)
 {
        unsigned int val;
 
-       val = omap_readl(clk->enable_reg);
+       val = __raw_readl(clk->enable_reg);
        if (rate == 12000000)
                val &= ~(1 << clk->enable_bit);
        else if (rate == 48000000)
                val |= (1 << clk->enable_bit);
        else
                return -EINVAL;
-       omap_writel(val, clk->enable_reg);
+       __raw_writel(val, clk->enable_reg);
        clk->rate = rate;
 
        return 0;
@@ -398,8 +398,8 @@ static int omap1_set_ext_clk_rate(struct clk * clk, unsigned long rate)
        else
                ratio_bits = (dsor - 2) << 2;
 
-       ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
-       omap_writew(ratio_bits, clk->enable_reg);
+       ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
+       __raw_writew(ratio_bits, clk->enable_reg);
 
        return 0;
 }
@@ -440,8 +440,8 @@ static void omap1_init_ext_clk(struct clk * clk)
        __u16 ratio_bits;
 
        /* Determine current rate and ensure clock is based on 96MHz APLL */
-       ratio_bits = omap_readw(clk->enable_reg) & ~1;
-       omap_writew(ratio_bits, clk->enable_reg);
+       ratio_bits = __raw_readw(clk->enable_reg) & ~1;
+       __raw_writew(ratio_bits, clk->enable_reg);
 
        ratio_bits = (ratio_bits & 0xfc) >> 2;
        if (ratio_bits > 6)
@@ -499,32 +499,20 @@ static int omap1_clk_enable_generic(struct clk *clk)
        if (clk->flags & ALWAYS_ENABLED)
                return 0;
 
-       if (unlikely(clk->enable_reg == 0)) {
+       if (unlikely(clk->enable_reg == NULL)) {
                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
                       clk->name);
                return -EINVAL;
        }
 
        if (clk->flags & ENABLE_REG_32BIT) {
-               if (clk->flags & VIRTUAL_IO_ADDRESS) {
-                       regval32 = __raw_readl(clk->enable_reg);
-                       regval32 |= (1 << clk->enable_bit);
-                       __raw_writel(regval32, clk->enable_reg);
-               } else {
-                       regval32 = omap_readl(clk->enable_reg);
-                       regval32 |= (1 << clk->enable_bit);
-                       omap_writel(regval32, clk->enable_reg);
-               }
+               regval32 = __raw_readl(clk->enable_reg);
+               regval32 |= (1 << clk->enable_bit);
+               __raw_writel(regval32, clk->enable_reg);
        } else {
-               if (clk->flags & VIRTUAL_IO_ADDRESS) {
-                       regval16 = __raw_readw(clk->enable_reg);
-                       regval16 |= (1 << clk->enable_bit);
-                       __raw_writew(regval16, clk->enable_reg);
-               } else {
-                       regval16 = omap_readw(clk->enable_reg);
-                       regval16 |= (1 << clk->enable_bit);
-                       omap_writew(regval16, clk->enable_reg);
-               }
+               regval16 = __raw_readw(clk->enable_reg);
+               regval16 |= (1 << clk->enable_bit);
+               __raw_writew(regval16, clk->enable_reg);
        }
 
        return 0;
@@ -535,29 +523,17 @@ static void omap1_clk_disable_generic(struct clk *clk)
        __u16 regval16;
        __u32 regval32;
 
-       if (clk->enable_reg == 0)
+       if (clk->enable_reg == NULL)
                return;
 
        if (clk->flags & ENABLE_REG_32BIT) {
-               if (clk->flags & VIRTUAL_IO_ADDRESS) {
-                       regval32 = __raw_readl(clk->enable_reg);
-                       regval32 &= ~(1 << clk->enable_bit);
-                       __raw_writel(regval32, clk->enable_reg);
-               } else {
-                       regval32 = omap_readl(clk->enable_reg);
-                       regval32 &= ~(1 << clk->enable_bit);
-                       omap_writel(regval32, clk->enable_reg);
-               }
+               regval32 = __raw_readl(clk->enable_reg);
+               regval32 &= ~(1 << clk->enable_bit);
+               __raw_writel(regval32, clk->enable_reg);
        } else {
-               if (clk->flags & VIRTUAL_IO_ADDRESS) {
-                       regval16 = __raw_readw(clk->enable_reg);
-                       regval16 &= ~(1 << clk->enable_bit);
-                       __raw_writew(regval16, clk->enable_reg);
-               } else {
-                       regval16 = omap_readw(clk->enable_reg);
-                       regval16 &= ~(1 << clk->enable_bit);
-                       omap_writew(regval16, clk->enable_reg);
-               }
+               regval16 = __raw_readw(clk->enable_reg);
+               regval16 &= ~(1 << clk->enable_bit);
+               __raw_writew(regval16, clk->enable_reg);
        }
 }
 
@@ -577,7 +553,7 @@ static long omap1_clk_round_rate(struct clk *clk, unsigned long rate)
                return clk->parent->rate / (1 << dsor_exp);
        }
 
-       if(clk->round_rate != 0)
+       if (clk->round_rate != NULL)
                return clk->round_rate(clk, rate);
 
        return clk->rate;
@@ -625,24 +601,17 @@ static void __init omap1_clk_disable_unused(struct clk *clk)
 
        /* Clocks in the DSP domain need api_ck. Just assume bootloader
         * has not enabled any DSP clocks */
-       if ((u32)clk->enable_reg == DSP_IDLECT2) {
+       if (clk->enable_reg == DSP_IDLECT2) {
                printk(KERN_INFO "Skipping reset check for DSP domain "
                       "clock \"%s\"\n", clk->name);
                return;
        }
 
        /* Is the clock already disabled? */
-       if (clk->flags & ENABLE_REG_32BIT) {
-               if (clk->flags & VIRTUAL_IO_ADDRESS)
-                       regval32 = __raw_readl(clk->enable_reg);
-                       else
-                               regval32 = omap_readl(clk->enable_reg);
-       } else {
-               if (clk->flags & VIRTUAL_IO_ADDRESS)
-                       regval32 = __raw_readw(clk->enable_reg);
-               else
-                       regval32 = omap_readw(clk->enable_reg);
-       }
+       if (clk->flags & ENABLE_REG_32BIT)
+               regval32 = __raw_readl(clk->enable_reg);
+       else
+               regval32 = __raw_readw(clk->enable_reg);
 
        if ((regval32 & (1 << clk->enable_bit)) == 0)
                return;
index 6eadf72828d8900ebbfbff69894b380cc5b80114..44eda0f83b3aa708a8457f4ee8917017609593d5 100644 (file)
@@ -174,7 +174,7 @@ static struct arm_idlect1_clk ck_dpll1out = {
                .parent         = &ck_dpll1,
                .flags          = CLOCK_IN_OMAP16XX | CLOCK_IDLE_CONTROL |
                                  ENABLE_REG_32BIT | RATE_PROPAGATES,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_CKOUT_ARM,
                .recalc         = &followparent_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -188,7 +188,7 @@ static struct clk sossi_ck = {
        .parent         = &ck_dpll1out.clk,
        .flags          = CLOCK_IN_OMAP16XX | CLOCK_NO_IDLE_PARENT |
                          ENABLE_REG_32BIT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_1,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1),
        .enable_bit     = 16,
        .recalc         = &omap1_sossi_recalc,
        .set_rate       = &omap1_set_sossi_rate,
@@ -215,7 +215,7 @@ static struct arm_idlect1_clk armper_ck = {
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                                  CLOCK_IN_OMAP310 | RATE_CKCTL |
                                  CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_PERCK,
                .rate_offset    = CKCTL_PERDIV_OFFSET,
                .recalc         = &omap1_ckctl_recalc,
@@ -229,7 +229,7 @@ static struct clk arm_gpio_ck = {
        .name           = "arm_gpio_ck",
        .parent         = &ck_dpll1,
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-       .enable_reg     = (void __iomem *)ARM_IDLECT2,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
        .enable_bit     = EN_GPIOCK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_generic,
@@ -242,7 +242,7 @@ static struct arm_idlect1_clk armxor_ck = {
                .parent         = &ck_ref,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                                  CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_XORPCK,
                .recalc         = &followparent_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -257,7 +257,7 @@ static struct arm_idlect1_clk armtim_ck = {
                .parent         = &ck_ref,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                                  CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_TIMCK,
                .recalc         = &followparent_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -272,7 +272,7 @@ static struct arm_idlect1_clk armwdt_ck = {
                .parent         = &ck_ref,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                                  CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_WDTCK,
                .recalc         = &omap1_watchdog_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -300,7 +300,7 @@ static struct clk dsp_ck = {
        .parent         = &ck_dpll1,
        .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          RATE_CKCTL,
-       .enable_reg     = (void __iomem *)ARM_CKCTL,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_CKCTL),
        .enable_bit     = EN_DSPCK,
        .rate_offset    = CKCTL_DSPDIV_OFFSET,
        .recalc         = &omap1_ckctl_recalc,
@@ -323,8 +323,8 @@ static struct clk dspper_ck = {
        .name           = "dspper_ck",
        .parent         = &ck_dpll1,
        .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         RATE_CKCTL | VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+                         RATE_CKCTL,
+       .enable_reg     = IOMEM(DSP_IDLECT2),
        .enable_bit     = EN_PERCK,
        .rate_offset    = CKCTL_PERDIV_OFFSET,
        .recalc         = &omap1_ckctl_recalc_dsp_domain,
@@ -336,9 +336,8 @@ static struct clk dspper_ck = {
 static struct clk dspxor_ck = {
        .name           = "dspxor_ck",
        .parent         = &ck_ref,
-       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = IOMEM(DSP_IDLECT2),
        .enable_bit     = EN_XORPCK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_dsp_domain,
@@ -348,9 +347,8 @@ static struct clk dspxor_ck = {
 static struct clk dsptim_ck = {
        .name           = "dsptim_ck",
        .parent         = &ck_ref,
-       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-                         VIRTUAL_IO_ADDRESS,
-       .enable_reg     = (void __iomem *)DSP_IDLECT2,
+       .flags          = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+       .enable_reg     = IOMEM(DSP_IDLECT2),
        .enable_bit     = EN_DSPTIMCK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_dsp_domain,
@@ -404,7 +402,7 @@ static struct clk l3_ocpi_ck = {
        .name           = "l3_ocpi_ck",
        .parent         = &tc_ck.clk,
        .flags          = CLOCK_IN_OMAP16XX,
-       .enable_reg     = (void __iomem *)ARM_IDLECT3,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT3),
        .enable_bit     = EN_OCPI_CK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_generic,
@@ -415,7 +413,7 @@ static struct clk tc1_ck = {
        .name           = "tc1_ck",
        .parent         = &tc_ck.clk,
        .flags          = CLOCK_IN_OMAP16XX,
-       .enable_reg     = (void __iomem *)ARM_IDLECT3,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT3),
        .enable_bit     = EN_TC1_CK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_generic,
@@ -426,7 +424,7 @@ static struct clk tc2_ck = {
        .name           = "tc2_ck",
        .parent         = &tc_ck.clk,
        .flags          = CLOCK_IN_OMAP16XX,
-       .enable_reg     = (void __iomem *)ARM_IDLECT3,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT3),
        .enable_bit     = EN_TC2_CK,
        .recalc         = &followparent_recalc,
        .enable         = &omap1_clk_enable_generic,
@@ -459,7 +457,7 @@ static struct arm_idlect1_clk api_ck = {
                .parent         = &tc_ck.clk,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                                  CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_APICK,
                .recalc         = &followparent_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -474,7 +472,7 @@ static struct arm_idlect1_clk lb_ck = {
                .parent         = &tc_ck.clk,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                                  CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_LBCK,
                .recalc         = &followparent_recalc,
                .enable         = &omap1_clk_enable_generic,
@@ -505,7 +503,7 @@ static struct clk lcd_ck_16xx = {
        .name           = "lcd_ck",
        .parent         = &ck_dpll1,
        .flags          = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL,
-       .enable_reg     = (void __iomem *)ARM_IDLECT2,
+       .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
        .enable_bit     = EN_LCDCK,
        .rate_offset    = CKCTL_LCDDIV_OFFSET,
        .recalc         = &omap1_ckctl_recalc,
@@ -519,7 +517,7 @@ static struct arm_idlect1_clk lcd_ck_1510 = {
                .parent         = &ck_dpll1,
                .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                                  RATE_CKCTL | CLOCK_IDLE_CONTROL,
-               .enable_reg     = (void __iomem *)ARM_IDLECT2,
+               .enable_reg     = OMAP1_IO_ADDRESS(ARM_IDLECT2),
                .enable_bit     = EN_LCDCK,
                .rate_offset    = CKCTL_LCDDIV_OFFSET,
                .recalc         = &omap1_ckctl_recalc,
@@ -537,7 +535,7 @@ static struct clk uart1_1510 = {
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                          ENABLE_REG_32BIT | ALWAYS_ENABLED |
                          CLOCK_NO_IDLE_PARENT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = 29,   /* Chooses between 12MHz and 48MHz */
        .set_rate       = &omap1_set_uart_rate,
        .recalc         = &omap1_uart_recalc,
@@ -553,7 +551,7 @@ static struct uart_clk uart1_16xx = {
                .rate           = 48000000,
                .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED |
                                  ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
-               .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+               .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
                .enable_bit     = 29,
                .enable         = &omap1_clk_enable_uart_functional,
                .disable        = &omap1_clk_disable_uart_functional,
@@ -569,7 +567,7 @@ static struct clk uart2_ck = {
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          CLOCK_IN_OMAP310 | ENABLE_REG_32BIT |
                          ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = 30,   /* Chooses between 12MHz and 48MHz */
        .set_rate       = &omap1_set_uart_rate,
        .recalc         = &omap1_uart_recalc,
@@ -585,7 +583,7 @@ static struct clk uart3_1510 = {
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                          ENABLE_REG_32BIT | ALWAYS_ENABLED |
                          CLOCK_NO_IDLE_PARENT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = 31,   /* Chooses between 12MHz and 48MHz */
        .set_rate       = &omap1_set_uart_rate,
        .recalc         = &omap1_uart_recalc,
@@ -601,7 +599,7 @@ static struct uart_clk uart3_16xx = {
                .rate           = 48000000,
                .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED |
                                  ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
-               .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+               .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
                .enable_bit     = 31,
                .enable         = &omap1_clk_enable_uart_functional,
                .disable        = &omap1_clk_disable_uart_functional,
@@ -615,7 +613,7 @@ static struct clk usb_clko = {      /* 6 MHz output on W4_USB_CLKO */
        .rate           = 6000000,
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT,
-       .enable_reg     = (void __iomem *)ULPD_CLOCK_CTRL,
+       .enable_reg     = OMAP1_IO_ADDRESS(ULPD_CLOCK_CTRL),
        .enable_bit     = USB_MCLK_EN_BIT,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -627,7 +625,7 @@ static struct clk usb_hhc_ck1510 = {
        .rate           = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 |
                          RATE_FIXED | ENABLE_REG_32BIT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = USB_HOST_HHC_UHOST_EN,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -640,7 +638,7 @@ static struct clk usb_hhc_ck16xx = {
        /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
        .flags          = CLOCK_IN_OMAP16XX |
                          RATE_FIXED | ENABLE_REG_32BIT,
-       .enable_reg     = (void __iomem *)OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
+       .enable_reg     = OMAP1_IO_ADDRESS(OTG_BASE + 0x08), /* OTG_SYSCON_2 */
        .enable_bit     = 8 /* UHOST_EN */,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -651,7 +649,7 @@ static struct clk usb_dc_ck = {
        /* Direct from ULPD, no parent */
        .rate           = 48000000,
        .flags          = CLOCK_IN_OMAP16XX | RATE_FIXED,
-       .enable_reg     = (void __iomem *)SOFT_REQ_REG,
+       .enable_reg     = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
        .enable_bit     = 4,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -662,7 +660,7 @@ static struct clk mclk_1510 = {
        /* Direct from ULPD, no parent. May be enabled by ext hardware. */
        .rate           = 12000000,
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED,
-       .enable_reg     = (void __iomem *)SOFT_REQ_REG,
+       .enable_reg     = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
        .enable_bit     = 6,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -672,7 +670,7 @@ static struct clk mclk_16xx = {
        .name           = "mclk",
        /* Direct from ULPD, no parent. May be enabled by ext hardware. */
        .flags          = CLOCK_IN_OMAP16XX,
-       .enable_reg     = (void __iomem *)COM_CLK_DIV_CTRL_SEL,
+       .enable_reg     = OMAP1_IO_ADDRESS(COM_CLK_DIV_CTRL_SEL),
        .enable_bit     = COM_ULPD_PLL_CLK_REQ,
        .set_rate       = &omap1_set_ext_clk_rate,
        .round_rate     = &omap1_round_ext_clk_rate,
@@ -694,7 +692,7 @@ static struct clk bclk_16xx = {
        .name           = "bclk",
        /* Direct from ULPD, no parent. May be enabled by ext hardware. */
        .flags          = CLOCK_IN_OMAP16XX,
-       .enable_reg     = (void __iomem *)SWD_CLK_DIV_CTRL_SEL,
+       .enable_reg     = OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL),
        .enable_bit     = SWD_ULPD_PLL_CLK_REQ,
        .set_rate       = &omap1_set_ext_clk_rate,
        .round_rate     = &omap1_round_ext_clk_rate,
@@ -705,14 +703,13 @@ static struct clk bclk_16xx = {
 
 static struct clk mmc1_ck = {
        .name           = "mmc_ck",
-       .id             = 1,
        /* Functional clock is direct from ULPD, interface clock is ARMPER */
        .parent         = &armper_ck.clk,
        .rate           = 48000000,
        .flags          = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
                          CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT |
                          CLOCK_NO_IDLE_PARENT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = 23,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
@@ -720,13 +717,13 @@ static struct clk mmc1_ck = {
 
 static struct clk mmc2_ck = {
        .name           = "mmc_ck",
-       .id             = 2,
+       .id             = 1,
        /* Functional clock is direct from ULPD, interface clock is ARMPER */
        .parent         = &armper_ck.clk,
        .rate           = 48000000,
        .flags          = CLOCK_IN_OMAP16XX |
                          RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
-       .enable_reg     = (void __iomem *)MOD_CONF_CTRL_0,
+       .enable_reg     = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
        .enable_bit     = 20,
        .enable         = &omap1_clk_enable_generic,
        .disable        = &omap1_clk_disable_generic,
index ab708d4c597e85e3aa0e1ac844995ac1c7d87bc8..e89d241144cbe46362d6af16642c8e3e06c82b88 100644 (file)
@@ -22,6 +22,7 @@
 #include <mach/board.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
+#include <mach/mmc.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -99,9 +100,98 @@ static inline void omap_init_mbox(void)
 static inline void omap_init_mbox(void) { }
 #endif
 
+/*-------------------------------------------------------------------------*/
+
+#if    defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
+                       int controller_nr)
+{
+       if (controller_nr == 0) {
+               omap_cfg_reg(MMC_CMD);
+               omap_cfg_reg(MMC_CLK);
+               omap_cfg_reg(MMC_DAT0);
+               if (cpu_is_omap1710()) {
+                       omap_cfg_reg(M15_1710_MMC_CLKI);
+                       omap_cfg_reg(P19_1710_MMC_CMDDIR);
+                       omap_cfg_reg(P20_1710_MMC_DATDIR0);
+               }
+               if (mmc_controller->slots[0].wire4) {
+                       omap_cfg_reg(MMC_DAT1);
+                       /* NOTE: DAT2 can be on W10 (here) or M15 */
+                       if (!mmc_controller->slots[0].nomux)
+                               omap_cfg_reg(MMC_DAT2);
+                       omap_cfg_reg(MMC_DAT3);
+               }
+       }
+
+       /* Block 2 is on newer chips, and has many pinout options */
+       if (cpu_is_omap16xx() && controller_nr == 1) {
+               if (!mmc_controller->slots[1].nomux) {
+                       omap_cfg_reg(Y8_1610_MMC2_CMD);
+                       omap_cfg_reg(Y10_1610_MMC2_CLK);
+                       omap_cfg_reg(R18_1610_MMC2_CLKIN);
+                       omap_cfg_reg(W8_1610_MMC2_DAT0);
+                       if (mmc_controller->slots[1].wire4) {
+                               omap_cfg_reg(V8_1610_MMC2_DAT1);
+                               omap_cfg_reg(W15_1610_MMC2_DAT2);
+                               omap_cfg_reg(R10_1610_MMC2_DAT3);
+                       }
+
+                       /* These are needed for the level shifter */
+                       omap_cfg_reg(V9_1610_MMC2_CMDDIR);
+                       omap_cfg_reg(V5_1610_MMC2_DATDIR0);
+                       omap_cfg_reg(W19_1610_MMC2_DATDIR1);
+               }
+
+               /* Feedback clock must be set on OMAP-1710 MMC2 */
+               if (cpu_is_omap1710())
+                       omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
+                                       MOD_CONF_CTRL_1);
+       }
+}
+
+void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                       int nr_controllers)
+{
+       int i;
+
+       for (i = 0; i < nr_controllers; i++) {
+               unsigned long base, size;
+               unsigned int irq = 0;
+
+               if (!mmc_data[i])
+                       continue;
+
+               omap1_mmc_mux(mmc_data[i], i);
+
+               switch (i) {
+               case 0:
+                       base = OMAP1_MMC1_BASE;
+                       irq = INT_MMC;
+                       break;
+               case 1:
+                       if (!cpu_is_omap16xx())
+                               return;
+                       base = OMAP1_MMC2_BASE;
+                       irq = INT_1610_MMC2;
+                       break;
+               default:
+                       continue;
+               }
+               size = OMAP1_MMC_SIZE;
+
+               omap_mmc_add(i, base, size, irq, mmc_data[i]);
+       };
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 #if defined(CONFIG_OMAP_STI)
 
-#define OMAP1_STI_BASE         IO_ADDRESS(0xfffea000)
+#define OMAP1_STI_BASE         0xfffea000
 #define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400)
 
 static struct resource sti_resources[] = {
index da13c3e82850e46e274a78acc4e0d3aed803ddc1..4e79f3eacebe78be01c219a8f33e003420c510d3 100644 (file)
@@ -179,9 +179,6 @@ void __init omap_check_revision(void)
        case 0x17:
                system_rev |= 0x16;
                break;
-       case 0x24:
-               system_rev |= 0x24;
-               break;
        default:
                printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
        }
index 2baeaeb0c9004d2038a7c1fde8b398068de77810..7de7c69155840f2e84fddc23574bb9d74546afe5 100644 (file)
@@ -103,30 +103,6 @@ static inline void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk)
 { }
 #endif
 
-static int omap1_mcbsp_check(unsigned int id)
-{
-       /* REVISIT: Check correctly for number of registered McBSPs */
-       if (cpu_is_omap730()) {
-               if (id > OMAP_MAX_MCBSP_COUNT - 2) {
-                      printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
-                               id + 1);
-                      return -ENODEV;
-               }
-               return 0;
-       }
-
-       if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
-               if (id > OMAP_MAX_MCBSP_COUNT - 1) {
-                       printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n",
-                               id + 1);
-                       return -ENODEV;
-               }
-               return 0;
-       }
-
-       return -ENODEV;
-}
-
 static void omap1_mcbsp_request(unsigned int id)
 {
        /*
@@ -151,7 +127,6 @@ static void omap1_mcbsp_free(unsigned int id)
 }
 
 static struct omap_mcbsp_ops omap1_mcbsp_ops = {
-       .check          = omap1_mcbsp_check,
        .request        = omap1_mcbsp_request,
        .free           = omap1_mcbsp_free,
 };
@@ -160,7 +135,6 @@ static struct omap_mcbsp_ops omap1_mcbsp_ops = {
 static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP730_MCBSP1_BASE,
-               .virt_base      = io_p2v(OMAP730_MCBSP1_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_730_McBSP1RX,
@@ -169,7 +143,6 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP730_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP730_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_730_McBSP2RX,
@@ -187,7 +160,6 @@ static struct omap_mcbsp_platform_data omap730_mcbsp_pdata[] = {
 static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP1510_MCBSP1_BASE,
-               .virt_base      = OMAP1510_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_McBSP1RX,
@@ -197,7 +169,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
                },
        {
                .phys_base      = OMAP1510_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP1510_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
                .rx_irq         = INT_1510_SPI_RX,
@@ -206,7 +177,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1510_MCBSP3_BASE,
-               .virt_base      = OMAP1510_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_McBSP3RX,
@@ -225,7 +195,6 @@ static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
 static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP1610_MCBSP1_BASE,
-               .virt_base      = OMAP1610_MCBSP1_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP1_TX,
                .rx_irq         = INT_McBSP1RX,
@@ -235,7 +204,6 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1610_MCBSP2_BASE,
-               .virt_base      = io_p2v(OMAP1610_MCBSP2_BASE),
                .dma_rx_sync    = OMAP_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP2_TX,
                .rx_irq         = INT_1610_McBSP2_RX,
@@ -244,7 +212,6 @@ static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP1610_MCBSP3_BASE,
-               .virt_base      = OMAP1610_MCBSP3_BASE,
                .dma_rx_sync    = OMAP_DMA_MCBSP3_RX,
                .dma_tx_sync    = OMAP_DMA_MCBSP3_TX,
                .rx_irq         = INT_McBSP3RX,
@@ -270,6 +237,18 @@ int __init omap1_mcbsp_init(void)
                }
        }
 
+       if (cpu_is_omap730())
+               omap_mcbsp_count = OMAP730_MCBSP_PDATA_SZ;
+       if (cpu_is_omap15xx())
+               omap_mcbsp_count = OMAP15XX_MCBSP_PDATA_SZ;
+       if (cpu_is_omap16xx())
+               omap_mcbsp_count = OMAP16XX_MCBSP_PDATA_SZ;
+
+       mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
+                                                               GFP_KERNEL);
+       if (!mcbsp_ptr)
+               return -ENOMEM;
+
        if (cpu_is_omap730())
                omap_mcbsp_register_board_cfg(omap730_mcbsp_pdata,
                                                OMAP730_MCBSP_PDATA_SZ);
diff --git a/arch/arm/mach-omap1/mmu.c b/arch/arm/mach-omap1/mmu.c
new file mode 100644 (file)
index 0000000..75dd310
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * linux/arch/arm/mach-omap1/mmu.c
+ *
+ * Support for non-MPU OMAP1 MMUs.
+ *
+ * Copyright (C) 2002-2005 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *        and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include "mmu.h"
+#include <asm/tlbflush.h>
+#include <mach/dsp_common.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE  0xfff000
+
+#define MMUFAULT_MASK (OMAP_MMU_FAULT_ST_PERM |\
+                      OMAP_MMU_FAULT_ST_TLB_MISS |\
+                      OMAP_MMU_FAULT_ST_TRANS)
+
+static unsigned int get_cam_l_va_mask(u16 pgsz)
+{
+       switch (pgsz) {
+       case OMAP_MMU_CAM_PAGESIZE_1MB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB;
+       case OMAP_MMU_CAM_PAGESIZE_64KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB;
+       case OMAP_MMU_CAM_PAGESIZE_4KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB;
+       case OMAP_MMU_CAM_PAGESIZE_1KB:
+               return OMAP_MMU_CAM_L_VA_TAG_L1_MASK |
+                      OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB;
+       }
+       return 0;
+}
+
+#define get_cam_va_mask(pgsz) \
+       ((u32)OMAP_MMU_CAM_H_VA_TAG_H_MASK << 22 | \
+        (u32)get_cam_l_va_mask(pgsz) << 6)
+
+static int intmem_usecount;
+
+/* for safety */
+void dsp_mem_usecount_clear(void)
+{
+       if (intmem_usecount != 0) {
+               printk(KERN_WARNING
+                      "MMU: unbalanced memory request/release detected.\n"
+                      "         intmem_usecount is not zero at where "
+                      "it should be! ... fixed to be zero.\n");
+               intmem_usecount = 0;
+               omap_dsp_release_mem();
+       }
+}
+EXPORT_SYMBOL_GPL(dsp_mem_usecount_clear);
+
+void omap_mmu_itack(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, OMAP_MMU_IT_ACK_IT_ACK, OMAP_MMU_IT_ACK);
+}
+EXPORT_SYMBOL(omap_mmu_itack);
+
+static int omap1_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+       int ret = 0;
+
+       if (omap_mmu_internal_memory(mmu, addr)) {
+               if (intmem_usecount++ == 0)
+                       ret = omap_dsp_request_mem();
+       }
+
+       return ret;
+}
+
+static int omap1_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+       int ret = 0;
+
+       if (omap_mmu_internal_memory(mmu, addr)) {
+               if (--intmem_usecount == 0)
+                       omap_dsp_release_mem();
+       } else
+               ret = -EIO;
+
+       return ret;
+}
+
+static inline void
+omap1_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* read a TLB entry */
+       omap_mmu_write_reg(mmu, OMAP_MMU_LD_TLB_RD, OMAP_MMU_LD_TLB);
+
+       cr->cam_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_H);
+       cr->cam_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM_L);
+       cr->ram_h = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_H);
+       cr->ram_l = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM_L);
+}
+
+static inline void
+omap1_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* Set the CAM and RAM entries */
+       omap_mmu_write_reg(mmu, cr->cam_h, OMAP_MMU_CAM_H);
+       omap_mmu_write_reg(mmu, cr->cam_l, OMAP_MMU_CAM_L);
+       omap_mmu_write_reg(mmu, cr->ram_h, OMAP_MMU_RAM_H);
+       omap_mmu_write_reg(mmu, cr->ram_l, OMAP_MMU_RAM_L);
+}
+
+static ssize_t omap1_mmu_show(struct omap_mmu *mmu, char *buf,
+                             struct omap_mmu_tlb_lock *tlb_lock)
+{
+       int i, len;
+
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "ety P V size   cam_va     ram_pa ap\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 FA */
+
+       for (i = 0; i < mmu->nr_tlb_entries; i++) {
+               struct omap_mmu_tlb_entry ent;
+               struct cam_ram_regset cr;
+               struct omap_mmu_tlb_lock entry_lock;
+               char *pgsz_str, *ap_str;
+
+               /* read a TLB entry */
+               entry_lock.base   = tlb_lock->base;
+               entry_lock.victim = i;
+               omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+               ent.pgsz  = cr.cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd = cr.cam_l & OMAP_MMU_CAM_P;
+               ent.valid = cr.cam_l & OMAP_MMU_CAM_V;
+               ent.ap    = cr.ram_l & OMAP_MMU_RAM_L_AP_MASK;
+               ent.va = (u32)(cr.cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK) << 22 |
+                        (u32)(cr.cam_l & get_cam_l_va_mask(ent.pgsz)) << 6;
+               ent.pa = (unsigned long)cr.ram_h << 16 |
+                        (cr.ram_l & OMAP_MMU_RAM_L_RAM_LSB_MASK);
+
+               pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1KB)  ? " 1KB":
+                                                                    " ???";
+               ap_str = (ent.ap == OMAP_MMU_RAM_L_AP_RO) ? "RO":
+                        (ent.ap == OMAP_MMU_RAM_L_AP_FA) ? "FA":
+                        (ent.ap == OMAP_MMU_RAM_L_AP_NA) ? "NA":
+                                                          "??";
+
+               if (i == tlb_lock->base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock->base);
+               if (i == tlb_lock->victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock->victim);
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 FA */
+                              "%02d: %c %c %s 0x%06lx 0x%08lx %s\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa, ap_str);
+       }
+
+       return len;
+}
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+       int n = 0;
+
+       exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+       exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+static int omap1_mmu_startup(struct omap_mmu *mmu)
+{
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               dev_err(mmu->dev, "MMU %s: failed to allocate memory "
+                       "for vector table\n", mmu->name);
+               return -ENOMEM;
+       }
+
+       mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+       return 0;
+}
+
+static void omap1_mmu_shutdown(struct omap_mmu *mmu)
+{
+       exmap_clear_preserved_entries(mmu);
+
+       if (dspvect_page != NULL) {
+               unsigned long virt;
+
+               down_read(&mmu->exmap_sem);
+
+               virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+               flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+
+               up_read(&mmu->exmap_sem);
+       }
+}
+
+static inline unsigned long omap1_mmu_cam_va(struct cam_ram_regset *cr)
+{
+       unsigned int page_size = cr->cam_l & OMAP_MMU_CAM_PAGESIZE_MASK;
+
+       return (u32)(cr->cam_h & OMAP_MMU_CAM_H_VA_TAG_H_MASK)  << 22 |
+              (u32)(cr->cam_l & get_cam_l_va_mask(page_size)) << 6;
+}
+
+static struct cam_ram_regset *
+omap1_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+       struct cam_ram_regset *cr;
+
+       if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+               dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
+                       " an aligned boundary\n", mmu->name, entry->va);
+               return ERR_PTR(-EINVAL);
+       }
+
+       cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+       cr->cam_h = entry->va >> 22;
+       cr->cam_l = (entry->va >> 6 & get_cam_l_va_mask(entry->pgsz)) |
+                  entry->prsvd | entry->pgsz;
+       cr->ram_h = entry->pa >> 16;
+       cr->ram_l = (entry->pa & OMAP_MMU_RAM_L_RAM_LSB_MASK) | entry->ap;
+
+       return cr;
+}
+
+static inline int omap1_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+       return cr->cam_l & OMAP_MMU_CAM_V;
+}
+
+static void omap1_mmu_interrupt(struct omap_mmu *mmu)
+{
+       unsigned long status;
+       unsigned long adh, adl;
+       unsigned long dp;
+       unsigned long va;
+
+       status = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_ST);
+       adh = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_H);
+       adl = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD_L);
+       dp = adh & OMAP_MMU_FAULT_AD_H_DP;
+       va = (((adh & OMAP_MMU_FAULT_AD_H_ADR_MASK) << 16) | adl);
+
+       /* if the fault is masked, nothing to do */
+       if ((status & MMUFAULT_MASK) == 0) {
+               pr_debug("MMU interrupt, but ignoring.\n");
+               /*
+                * note: in OMAP1710,
+                * when CACHE + DMA domain gets out of idle in DSP,
+                * MMU interrupt occurs but MMU_FAULT_ST is not set.
+                * in this case, we just ignore the interrupt.
+                */
+               if (status) {
+                       pr_debug("%s%s%s%s\n",
+                                (status & OMAP_MMU_FAULT_ST_PREF)?
+                                "  (prefetch err)" : "",
+                                (status & OMAP_MMU_FAULT_ST_PERM)?
+                                "  (permission fault)" : "",
+                                (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+                                "  (TLB miss)" : "",
+                                (status & OMAP_MMU_FAULT_ST_TRANS) ?
+                                "  (translation fault)": "");
+                       pr_debug("fault address = %#08lx\n", va);
+               }
+               enable_irq(mmu->irq);
+               return;
+       }
+
+       pr_info("%s%s%s%s\n",
+               (status & OMAP_MMU_FAULT_ST_PREF)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PREF)?
+               "  prefetch err":
+               "  (prefetch err)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_PERM)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_PERM)?
+               "  permission fault":
+               "  (permission fault)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_TLB_MISS)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TLB_MISS)?
+               "  TLB miss":
+               "  (TLB miss)":
+               "",
+               (status & OMAP_MMU_FAULT_ST_TRANS)?
+               (MMUFAULT_MASK & OMAP_MMU_FAULT_ST_TRANS)?
+               "  translation fault":
+               "  (translation fault)":
+               "");
+       pr_info("fault address = %#08lx\n", va);
+
+       mmu->fault_address = va;
+       schedule_work(&mmu->irq_work);
+}
+
+static pgprot_t omap1_mmu_pte_get_attr(struct omap_mmu_tlb_entry *entry)
+{
+       /* 4KB AP position as default */
+       u32 attr = entry->ap >> 4;
+       attr <<= ((entry->pgsz == OMAP_MMU_CAM_PAGESIZE_1MB) ? 6:0);
+       return attr;
+}
+
+struct omap_mmu_ops omap1_mmu_ops = {
+       .startup        = omap1_mmu_startup,
+       .shutdown       = omap1_mmu_shutdown,
+       .mem_enable     = omap1_mmu_mem_enable,
+       .mem_disable    = omap1_mmu_mem_disable,
+       .read_tlb       = omap1_mmu_read_tlb,
+       .load_tlb       = omap1_mmu_load_tlb,
+       .show           = omap1_mmu_show,
+       .cam_va         = omap1_mmu_cam_va,
+       .cam_ram_alloc  = omap1_mmu_cam_ram_alloc,
+       .cam_ram_valid  = omap1_mmu_cam_ram_valid,
+       .interrupt      = omap1_mmu_interrupt,
+       .pte_get_attr   = omap1_mmu_pte_get_attr,
+};
+EXPORT_SYMBOL_GPL(omap1_mmu_ops);
diff --git a/arch/arm/mach-omap1/mmu.h b/arch/arm/mach-omap1/mmu.h
new file mode 100644 (file)
index 0000000..b0255af
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef __MACH_OMAP1_MMU_H
+#define __MACH_OMAP1_MMU_H
+
+#include <linux/io.h>
+#include <mach/mmu.h>
+
+#define MMU_LOCK_BASE_MASK             (0x3f << 10)
+#define MMU_LOCK_VICTIM_MASK           (0x3f << 4)
+
+#define OMAP_MMU_PREFETCH              0x00
+#define OMAP_MMU_WALKING_ST            0x04
+#define OMAP_MMU_CNTL                  0x08
+#define OMAP_MMU_FAULT_AD_H            0x0c
+#define OMAP_MMU_FAULT_AD_L            0x10
+#define OMAP_MMU_FAULT_ST              0x14
+#define OMAP_MMU_IT_ACK                        0x18
+#define OMAP_MMU_TTB_H                 0x1c
+#define OMAP_MMU_TTB_L                 0x20
+#define OMAP_MMU_LOCK                  0x24
+#define OMAP_MMU_LD_TLB                        0x28
+#define OMAP_MMU_CAM_H                 0x2c
+#define OMAP_MMU_CAM_L                 0x30
+#define OMAP_MMU_RAM_H                 0x34
+#define OMAP_MMU_RAM_L                 0x38
+#define OMAP_MMU_GFLUSH                        0x3c
+#define OMAP_MMU_FLUSH_ENTRY           0x40
+#define OMAP_MMU_READ_CAM_H            0x44
+#define OMAP_MMU_READ_CAM_L            0x48
+#define OMAP_MMU_READ_RAM_H            0x4c
+#define OMAP_MMU_READ_RAM_L            0x50
+
+#define OMAP_MMU_CNTL_BURST_16MNGT_EN  0x0020
+#define OMAP_MMU_CNTL_WTL_EN           0x0004
+#define OMAP_MMU_CNTL_MMU_EN           0x0002
+#define OMAP_MMU_CNTL_RESET_SW         0x0001
+
+#define OMAP_MMU_FAULT_AD_H_DP         0x0100
+#define OMAP_MMU_FAULT_AD_H_ADR_MASK   0x00ff
+
+#define OMAP_MMU_FAULT_ST_PREF         0x0008
+#define OMAP_MMU_FAULT_ST_PERM         0x0004
+#define OMAP_MMU_FAULT_ST_TLB_MISS     0x0002
+#define OMAP_MMU_FAULT_ST_TRANS                0x0001
+
+#define OMAP_MMU_IT_ACK_IT_ACK         0x0001
+
+#define OMAP_MMU_CAM_H_VA_TAG_H_MASK           0x0003
+
+#define OMAP_MMU_CAM_L_VA_TAG_L1_MASK          0xc000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1MB      0x0000
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_64KB     0x3c00
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_4KB      0x3fc0
+#define OMAP_MMU_CAM_L_VA_TAG_L2_MASK_1KB      0x3ff0
+#define OMAP_MMU_CAM_L_P                       0x0008
+#define OMAP_MMU_CAM_L_V                       0x0004
+#define OMAP_MMU_CAM_L_PAGESIZE_MASK           0x0003
+#define OMAP_MMU_CAM_L_PAGESIZE_1MB            0x0000
+#define OMAP_MMU_CAM_L_PAGESIZE_64KB           0x0001
+#define OMAP_MMU_CAM_L_PAGESIZE_4KB            0x0002
+#define OMAP_MMU_CAM_L_PAGESIZE_1KB            0x0003
+
+#define OMAP_MMU_CAM_P                 OMAP_MMU_CAM_L_P
+#define OMAP_MMU_CAM_V                 OMAP_MMU_CAM_L_V
+#define OMAP_MMU_CAM_PAGESIZE_MASK     OMAP_MMU_CAM_L_PAGESIZE_MASK
+#define OMAP_MMU_CAM_PAGESIZE_1MB      OMAP_MMU_CAM_L_PAGESIZE_1MB
+#define OMAP_MMU_CAM_PAGESIZE_64KB     OMAP_MMU_CAM_L_PAGESIZE_64KB
+#define OMAP_MMU_CAM_PAGESIZE_4KB      OMAP_MMU_CAM_L_PAGESIZE_4KB
+#define OMAP_MMU_CAM_PAGESIZE_1KB      OMAP_MMU_CAM_L_PAGESIZE_1KB
+#define OMAP_MMU_CAM_PAGESIZE_16MB     -1 /* unused in omap1 */
+
+#define OMAP_MMU_RAM_L_RAM_LSB_MASK    0xfc00
+#define OMAP_MMU_RAM_L_AP_MASK         0x0300
+#define OMAP_MMU_RAM_L_AP_NA           0x0000
+#define OMAP_MMU_RAM_L_AP_RO           0x0200
+#define OMAP_MMU_RAM_L_AP_FA           0x0300
+
+#define OMAP_MMU_LD_TLB_RD             0x0002
+
+#define INIT_TLB_ENTRY(ent, v, p, ps)                  \
+do {                                                   \
+       (ent)->va       = (v);                          \
+       (ent)->pa       = (p);                          \
+       (ent)->pgsz     = (ps);                         \
+       (ent)->prsvd    = 0;                            \
+       (ent)->ap       = OMAP_MMU_RAM_L_AP_FA;         \
+       (ent)->tlb      = 1;                            \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent, v, p)        \
+do {                                                   \
+       (ent)->va       = (v);                          \
+       (ent)->pa       = (p);                          \
+       (ent)->pgsz     = OMAP_MMU_CAM_PAGESIZE_4KB;    \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;               \
+       (ent)->ap       = OMAP_MMU_RAM_L_AP_FA;         \
+} while (0)
+
+struct omap_mmu_tlb_entry {
+       unsigned long va;
+       unsigned long pa;
+       unsigned int pgsz, prsvd, valid;
+
+       u16 ap;
+       unsigned int tlb;
+};
+
+static inline unsigned short
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+       return __raw_readw(mmu->base + reg);
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+                              unsigned short val, unsigned long reg)
+{
+       __raw_writew(val, mmu->base + reg);
+}
+
+#endif /* __MACH_OMAP1_MMU_H */
index 0e25a996bb4c17d65d02231bdb996647e56634f1..4965986b4ad56ee2ec794487ec606b3f670873c9 100644 (file)
@@ -67,8 +67,8 @@ static void __init omap_serial_reset(struct plat_serial8250_port *p)
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART1_BASE),
-               .mapbase        = (unsigned long)OMAP_UART1_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART1_BASE),
+               .mapbase        = OMAP_UART1_BASE,
                .irq            = INT_UART1,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
@@ -76,8 +76,8 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART2_BASE),
-               .mapbase        = (unsigned long)OMAP_UART2_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART2_BASE),
+               .mapbase        = OMAP_UART2_BASE,
                .irq            = INT_UART2,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
@@ -85,8 +85,8 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .uartclk        = OMAP16XX_BASE_BAUD * 16,
        },
        {
-               .membase        = (char*)IO_ADDRESS(OMAP_UART3_BASE),
-               .mapbase        = (unsigned long)OMAP_UART3_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART3_BASE),
+               .mapbase        = OMAP_UART3_BASE,
                .irq            = INT_UART3,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
index 7069c9d536f1b07ad07460a9909cb050be8d013c..362edfa4117286e3efe3cd4a7cc7ea31e20ec5a3 100644 (file)
@@ -14,24 +14,131 @@ config ARCH_OMAP2420
 config ARCH_OMAP2430
        bool "OMAP2430 support"
        depends on ARCH_OMAP24XX
+       select ARCH_OMAP_OTG
+
+config ARCH_OMAP34XX
+       bool "OMAP34xx Based System"
+       depends on ARCH_OMAP3
+
+config ARCH_OMAP3430
+       bool "OMAP3430 support"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+       select ARCH_OMAP_OTG
 
 comment "OMAP Board Type"
-       depends on ARCH_OMAP2
+       depends on ARCH_OMAP2 || ARCH_OMAP3
 
 config MACH_OMAP_GENERIC
        bool "Generic OMAP board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
+config MACH_NOKIA_N800
+       bool "Nokia N800"
+       depends on ARCH_OMAP2420
+       select VIDEO_TCM825X if VIDEO_OMAP2 && VIDEO_HELPER_CHIPS_AUTO
+       select CBUS if VIDEO_TCM825X
+       select CBUS_RETU if VIDEO_TCM825X
+       select MENELAUS if VIDEO_TCM825X
+       select OMAP_GPIO_SWITCH
+
+config MACH_NOKIA_N810
+       bool "Nokia N810"
+       depends on MACH_NOKIA_N800
+
+config MACH_NOKIA_N810_WIMAX
+       bool "Nokia N810 WiMAX"
+       depends on MACH_NOKIA_N800
+       select MACH_NOKIA_N810
+
+config MACH_OMAP2_TUSB6010
+       bool
+       depends on ARCH_OMAP2 && ARCH_OMAP2420
+       default y if MACH_NOKIA_N800
+
 config MACH_OMAP_H4
        bool "OMAP 2420 H4 board"
-       depends on ARCH_OMAP2 && ARCH_OMAP24XX
+       depends on ARCH_OMAP2 && ARCH_OMAP2420
        select OMAP_DEBUG_DEVICES
+       select GPIOEXPANDER_OMAP
+
+config MACH_OMAP_H4_TUSB
+       bool "TUSB 6010 EVM board"
+       depends on MACH_OMAP_H4
+       select MACH_OMAP2_TUSB6010
+       help
+         Set this if you've got a TUSB6010 high speed USB board.
+         You may need to consult the schematics for your revisions
+         of the Menelaus and TUSB boards, and make changes to be
+         sure this is set up properly for your board stack.
+
+         Be sure to select OTG mode operation, not host-only or
+         peripheral-only.
+
+config MACH_OMAP_H4_OTG
+       bool "Use USB OTG connector, not device connector (S1.10)"
+       depends on MACH_OMAP_H4
+       help
+         Set this if you've set S1.10 (on the mainboard) to use the
+         Mini-AB (OTG) connector and OTG transceiver with the USB0
+         port, instead of the Mini-B ("download") connector with its
+         non-OTG transceiver.
+
+         Note that the "download" connector can be used to bootstrap
+         the system from the OMAP mask ROM.  Also, since this is a
+         development platform, you can also force the OTG port into
+         a non-OTG operational mode.
+
+config MACH_OMAP2_H4_USB1
+       bool "Use USB1 port, not UART2 (S3.3)"
+       depends on MACH_OMAP_H4
+       help
+         Set this if you've set SW3.3 (on the CPU card) so that the
+         expansion connectors receive USB1 signals instead of UART2.
 
 config MACH_OMAP_APOLLON
        bool "OMAP 2420 Apollon board"
-       depends on ARCH_OMAP2 && ARCH_OMAP24XX
+       depends on ARCH_OMAP2 && ARCH_OMAP2420
 
 config MACH_OMAP_2430SDP
        bool "OMAP 2430 SDP board"
+       depends on ARCH_OMAP2 && ARCH_OMAP2430
+
+config MACH_OMAP_LDP
+       bool "OMAP 3 LDP board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP2EVM 
+       bool "OMAP 2530 EVM board"
        depends on ARCH_OMAP2 && ARCH_OMAP24XX
 
+config MACH_OMAP_3430SDP
+       bool "OMAP 3430 SDP board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP3EVM
+       bool "OMAP 3530 EVM board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP3_BEAGLE
+       bool "OMAP3 BEAGLE board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OVERO
+       bool "Gumstix Overo board"
+       depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config OMAP_TICK_GPTIMER
+       int "GPTIMER used for system tick timer"
+       depends on ARCH_OMAP2 || ARCH_OMAP3
+       range 1 12
+       default 1
+       help
+         Linux uses one of the twelve on-board OMAP GPTIMER blocks to generate
+         system tick interrupts.  The twelve GPTIMERs have slightly
+         different powerdomain, source clock, and security properties
+         (mostly documented in the OMAP3 TRMs) that can affect the selection
+         of which GPTIMER to use.  The historical default is GPTIMER1.
+         If CONFIG_OMAP_32K_TIMER is selected, Beagle may require GPTIMER12
+         due to hardware sensitivity to glitches on the OMAP 32kHz clock
+         input.
+
index 93ee990618ef32b0905dd5de7bc515aa5a70c14d..33de217cecb1deee61bb744f25f5c235b713a6a8 100644 (file)
@@ -3,25 +3,82 @@
 #
 
 # Common support
-obj-y := irq.o id.o io.o memory.o control.o prcm.o clock.o mux.o \
-               devices.o serial.o gpmc.o timer-gp.o
+obj-y := irq.o id.o io.o sdrc.o control.o prcm.o clock.o mux.o \
+               devices.o serial.o gpmc.o timer-gp.o powerdomain.o \
+               clockdomain.o
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 
 # Functions loaded to SRAM
 obj-$(CONFIG_ARCH_OMAP2420)            += sram242x.o
 obj-$(CONFIG_ARCH_OMAP2430)            += sram243x.o
+obj-$(CONFIG_ARCH_OMAP3)               += sram34xx.o
+
+# SMS/SDRC
+obj-$(CONFIG_ARCH_OMAP2)               += sdrc2xxx.o
+# obj-$(CONFIG_ARCH_OMAP3)             += sdrc3xxx.o
 
 # Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
+ifeq ($(CONFIG_PM),y)
+obj-y                                  += pm.o
+obj-$(CONFIG_ARCH_OMAP2)               += pm24xx.o
+obj-$(CONFIG_ARCH_OMAP24XX)            += sleep24xx.o
+obj-$(CONFIG_ARCH_OMAP3)               += pm34xx.o sleep34xx.o
+obj-$(CONFIG_PM_DEBUG)                 += pm-debug.o
+endif
+
+# SmartReflex driver
+obj-$(CONFIG_OMAP_SMARTREFLEX)         += smartreflex.o
 
 # Clock framework
 obj-$(CONFIG_ARCH_OMAP2)               += clock24xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += clock34xx.o
 
+# DSP
+obj-$(CONFIG_OMAP_MMU_FWK)     += mmu_mach.o
+obj-$(CONFIG_OMAP_MBOX_FWK)    += mailbox_mach.o
+mailbox_mach-objs              := mailbox.o
+mmu_mach-objs                  := mmu.o
+
 # Specific board support
 obj-$(CONFIG_MACH_OMAP_GENERIC)                += board-generic.o
-obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o
-obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o
-obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o
+obj-$(CONFIG_MACH_OMAP_H4)             += board-h4.o board-h4-mmc.o
+obj-$(CONFIG_MACH_OMAP_2430SDP)                += board-2430sdp.o \
+                                          board-2430sdp-flash.o \
+                                          hsmmc.o \
+                                          usb-musb.o \
+                                          usb-ehci.o
+obj-$(CONFIG_MACH_OMAP2EVM)            += board-omap2evm.o \
+                                          hsmmc.o
+obj-$(CONFIG_MACH_OMAP_3430SDP)                += board-3430sdp.o \
+                                          hsmmc.o \
+                                          usb-musb.o \
+                                          usb-ehci.o \
+                                          board-3430sdp-flash.o
+obj-$(CONFIG_MACH_OMAP3EVM)            += board-omap3evm.o \
+                                          hsmmc.o \
+                                          usb-musb.o usb-ehci.o \
+                                          board-omap3evm-flash.o
+obj-$(CONFIG_MACH_OMAP3_BEAGLE)                += board-omap3beagle.o \
+                                          usb-musb.o usb-ehci.o \
+                                          hsmmc.o
+obj-$(CONFIG_MACH_OMAP_LDP)            += board-ldp.o \
+                                          hsmmc.o \
+                                          usb-musb.o
+obj-$(CONFIG_MACH_OMAP_APOLLON)                += board-apollon.o \
+                                          board-apollon-mmc.o  \
+                                          board-apollon-keys.o
+obj-$(CONFIG_MACH_NOKIA_N800)          += board-n800.o board-n800-flash.o \
+                                          board-n800-mmc.o board-n800-bt.o \
+                                          board-n800-audio.o board-n800-usb.o \
+                                          board-n800-dsp.o \
+                                          board-n800-camera.o
+obj-$(CONFIG_MACH_NOKIA_N810)          += board-n810.o
+obj-$(CONFIG_MACH_OVERO)               += board-overo.o \
+                                          hsmmc.o \
+                                          usb-musb.o \
+                                          usb-ehci.o
+
+# TUSB 6010 chips
+obj-$(CONFIG_MACH_OMAP2_TUSB6010)      += usb-tusb6010.o
 
diff --git a/arch/arm/mach-omap2/board-2430sdp-flash.c b/arch/arm/mach-omap2/board-2430sdp-flash.c
new file mode 100644 (file)
index 0000000..57d3b55
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * linux/arch/arm/mach-omap2/board-2430sdp-flash.c
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ * Author: Kevin Hilman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach/flash.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+#define ONENAND_MAP 0x20000000
+#define GPMC_OFF_CONFIG1_0 0x60
+
+enum fstype {
+       NAND = 0,
+       NOR,
+       ONENAND,
+       UNKNOWN = -1
+};
+
+static enum fstype flash_type = NAND;
+
+static struct mtd_partition nand_partitions[] = {
+       {
+               .name           = "X-Loader",
+               .offset         = 0,
+               .size           = 4*(64*2048),  /* 0-3 blks reserved.
+                                                  Mandated by ROM code */
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "U-Boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           =  4*(64*2048),
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "U-Boot Environment",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 2*(64*2048),
+       },
+       {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 32*(64*2048),         /* 4*1M */
+       },
+       {
+               .name           = "File System",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+static struct omap_nand_platform_data sdp_nand_data = {
+       .parts          = nand_partitions,
+       .nr_parts       = ARRAY_SIZE(nand_partitions),
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &sdp_nand_data,
+       },
+};
+
+static struct mtd_partition onenand_partitions[] = {
+       {
+               .name           = "(OneNAND)X-Loader",
+               .offset         = 0,
+               .size           = 4*(64*2048),  /* 0-3 blks reserved.
+                                                  Mandated by ROM code */
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "(OneNAND)U-Boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           =  2*(64*2048),
+               .mask_flags     = MTD_WRITEABLE /* force read-only */
+       },
+       {
+               .name           = "(OneNAND)U-Boot Environment",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1*(64*2048),
+       },
+       {
+               .name           = "(OneNAND)Kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 4*(64*2048),
+       },
+       {
+               .name           = "(OneNAND)File System",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data sdp_onenand_data = {
+       .parts          = onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(onenand_partitions),
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &sdp_onenand_data,
+       },
+};
+
+void __init sdp2430_flash_init(void)
+{
+       void __iomem *gpmc_base_add, *gpmc_cs_base_add;
+       unsigned char cs = 0;
+
+       gpmc_base_add = (__force void __iomem *)OMAP243X_GPMC_VIRT;
+       while (cs < GPMC_CS_NUM) {
+               int ret = 0;
+
+               /* Each GPMC set for a single CS is at offset 0x30 */
+               gpmc_cs_base_add = (gpmc_base_add + GPMC_OFF_CONFIG1_0 +
+                                   (cs*0x30));
+
+               /* xloader/Uboot would have programmed the NAND/oneNAND
+                * base address for us This is a ugly hack. The proper
+                * way of doing this is to pass the setup of u-boot up
+                * to kernel using kernel params - something on the
+                * lines of machineID. Check if Nand/oneNAND is
+                * configured */
+               ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG1);
+               if ((ret & 0xC00) == (0x800)) {
+                       /* Found it!! */
+                       printk(KERN_INFO "NAND: Found NAND on CS %d \n", cs);
+                       flash_type = NAND;
+                       break;
+               }
+               ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG7);
+               if ((ret & 0x3F) == (ONENAND_MAP >> 24)) {
+                       /* Found it!! */
+                       flash_type = ONENAND;
+                       break;
+               }
+               cs++;
+       }
+       if (cs >= GPMC_CS_NUM) {
+               printk(KERN_INFO "MTD: Unable to find MTD configuration in "
+                                "GPMC   - not registering.\n");
+               return;
+       }
+
+       if (flash_type == NAND) {
+               sdp_nand_data.cs               = cs;
+               sdp_nand_data.gpmc_cs_baseaddr = gpmc_cs_base_add;
+               sdp_nand_data.gpmc_baseaddr    = gpmc_base_add;
+
+               if (platform_device_register(&sdp_nand_device) < 0) {
+                       printk(KERN_ERR "Unable to register NAND device\n");
+                       return;
+               }
+       }
+
+       if (flash_type == ONENAND) {
+               sdp_onenand_data.cs = cs;
+
+               if (platform_device_register(&sdp_onenand_device) < 0) {
+                       printk(KERN_ERR "Unable to register OneNAND device\n");
+                       return;
+               }
+       }
+}
index b72ca13b3acb7038e472ac83e01e369b4bfa9a68..cea2540725e6e80e412ed1fda0d0b4e981c53eb7 100644 (file)
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/i2c/twl4030.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/gpio.h>
 #include <mach/mux.h>
 #include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/hsmmc.h>
 #include <mach/common.h>
+#include <mach/keypad.h>
 #include <mach/gpmc.h>
+#include <mach/mcspi.h>
 
 #include <asm/io.h>
 
-
 #define        SDP2430_FLASH_CS        0
 #define        SDP2430_SMC91X_CS       5
 
+/* GPIO used for TSC2046 (touchscreen)
+ *
+ * Also note that the tsc2046 is the same silicon as the ads7846, so
+ * that driver is used for the touchscreen. */
+#define TS_GPIO                 24
+
+#define TWL4030_MSECURE_GPIO   118
+#define SECONDARY_LCD_GPIO     147
+
 static struct mtd_partition sdp2430_partitions[] = {
        /* bootloader (U-Boot, etc) in first sector */
        {
@@ -107,6 +123,11 @@ static struct resource sdp2430_smc91x_resources[] = {
        },
 };
 
+static struct platform_device sdp2430_lcd_device = {
+       .name           = "sdp2430_lcd",
+       .id             = -1,
+};
+
 static struct platform_device sdp2430_smc91x_device = {
        .name           = "smc91x",
        .id             = -1,
@@ -114,9 +135,126 @@ static struct platform_device sdp2430_smc91x_device = {
        .resource       = sdp2430_smc91x_resources,
 };
 
+/*
+ * Key mapping for 2430 SDP board
+ */
+
+static int sdp2430_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(0, 4, KEY_C),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(1, 4, KEY_G),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(2, 4, KEY_3),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P),
+       KEY(3, 4, KEY_Q),
+       KEY(4, 0, KEY_R),
+       KEY(4, 1, KEY_4),
+       KEY(4, 2, KEY_T),
+       KEY(4, 3, KEY_U),
+       KEY(4, 4, KEY_D),
+       KEY(5, 0, KEY_V),
+       KEY(5, 1, KEY_W),
+       KEY(5, 2, KEY_L),
+       KEY(5, 3, KEY_S),
+       KEY(5, 4, KEY_H),
+       0
+};
+
+static struct twl4030_keypad_data sdp2430_kp_data = {
+       .rows           = 5,
+       .cols           = 6,
+       .keymap         = sdp2430_keymap,
+       .keymapsize     = ARRAY_SIZE(sdp2430_keymap),
+       .rep            = 1,
+       .irq            = TWL4030_MODIRQ_KEYPAD,
+};
+
+static int __init msecure_init(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+       ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+       if (ret < 0) {
+               printk(KERN_ERR "msecure_init: can't reserve GPIO:%d !\n",
+                       TWL4030_MSECURE_GPIO);
+               goto out;
+       }
+       /*
+        * TWL4030 will be in secure mode if msecure line from OMAP is low.
+        * Make msecure line high in order to change the TWL4030 RTC time
+        * and calender registers.
+        */
+       gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+out:
+#endif
+
+       return ret;
+}
+
 static struct platform_device *sdp2430_devices[] __initdata = {
        &sdp2430_smc91x_device,
        &sdp2430_flash_device,
+       &sdp2430_lcd_device,
+};
+
+static void ads7846_dev_init(void)
+{
+       if (omap_request_gpio(TS_GPIO) < 0)
+               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+
+       omap_set_gpio_direction(TS_GPIO, 1);
+
+       omap_set_gpio_debounce(TS_GPIO, 1);
+       omap_set_gpio_debounce_time(TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(TS_GPIO);
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+       .get_pendown_state = ads7846_get_pendown_state,
+       .keep_vref_on      = 1,
+};
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 0,  /* 0: slave, 1: master */
+};
+
+static struct omap_lcd_config sdp2430_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct spi_board_info sdp2430_spi_board_info[] __initdata = {
+       [0] = {
+               /*
+                * TSC2046 operates at a max freqency of 2MHz, so
+                * operate slightly below at 1.5MHz
+                */
+               .modalias        = "ads7846",
+               .bus_num         = 1,
+               .chip_select     = 0,
+               .max_speed_hz    = 1500000,
+               .controller_data = &tsc2046_mcspi_config,
+               .irq             = OMAP_GPIO_IRQ(TS_GPIO),
+               .platform_data   = &tsc2046_config,
+       },
 };
 
 static inline void __init sdp2430_init_smc91x(void)
@@ -184,7 +322,7 @@ out:
 
 static void __init omap_2430sdp_init_irq(void)
 {
-       omap2_init_common_hw();
+       omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
        sdp2430_init_smc91x();
@@ -194,16 +332,83 @@ 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[] = {
+static
+struct omap_serial_console_config sdp2430_serial_console_config __initdata = {
+       .console_uart = 1,
+       .console_speed = 115200,
+};
+
+static struct omap_board_config_kernel sdp2430_config[] __initdata = {
        {OMAP_TAG_UART, &sdp2430_uart_config},
+       {OMAP_TAG_LCD, &sdp2430_lcd_config},
+       {OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
+};
+
+
+static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data sdp2430_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data sdp2430_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data sdp2430_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .gpio           = &sdp2430_gpio_data,
+       .madc           = &sdp2430_madc_data,
+       .keypad         = &sdp2430_kp_data,
+       .usb            = &sdp2430_usb_data,
+};
+
+static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_24XX_SYS_NIRQ,
+               .platform_data = &sdp2430_twldata,
+       },
 };
 
+static int __init omap2430_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 400, NULL, 0);
+       omap_register_i2c_bus(2, 2600, sdp2430_i2c_boardinfo,
+                       ARRAY_SIZE(sdp2430_i2c_boardinfo));
+       return 0;
+}
+
 static void __init omap_2430sdp_init(void)
 {
+       omap2430_i2c_init();
+
        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();
+
+       msecure_init();
+
+       sdp2430_flash_init();
+       usb_musb_init();
+
+       spi_register_board_info(sdp2430_spi_board_info,
+                               ARRAY_SIZE(sdp2430_spi_board_info));
+       ads7846_dev_init();
+       hsmmc_init();
+
+       /* turn off secondary LCD backlight */
+       omap_set_gpio_direction(SECONDARY_LCD_GPIO, 0);
+       omap_set_gpio_dataout(SECONDARY_LCD_GPIO, 0);
 }
 
 static void __init omap_2430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-3430sdp-flash.c b/arch/arm/mach-omap2/board-3430sdp-flash.c
new file mode 100644 (file)
index 0000000..b16f70c
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * linux/arch/arm/mach-omap2/board-3430sdp-flash.c
+ *
+ * Copyright (c) 2007 Texas Instruments
+ *
+ * Modified from mach-omap2/board-2430sdp-flash.c
+ * Author: Rohit Choraria <rohitkc@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+static struct mtd_partition sdp_nor_partitions[] = {
+       /* bootloader (U-Boot, etc) in first sector */
+       {
+               .name           = "Bootloader-NOR",
+               .offset         = 0,
+               .size           = SZ_256K,
+               .mask_flags     = MTD_WRITEABLE, /* force read-only */
+       },
+       /* bootloader params in the next sector */
+       {
+               .name           = "Params-NOR",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_256K,
+               .mask_flags     = 0,
+       },
+       /* kernel */
+       {
+               .name           = "Kernel-NOR",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_2M,
+               .mask_flags     = 0
+       },
+       /* file system */
+       {
+               .name           = "Filesystem-NOR",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+               .mask_flags     = 0
+       }
+};
+
+static struct flash_platform_data sdp_nor_data = {
+       .map_name       = "cfi_probe",
+       .width          = 2,
+       .parts          = sdp_nor_partitions,
+       .nr_parts       = ARRAY_SIZE(sdp_nor_partitions),
+};
+
+static struct resource sdp_nor_resource = {
+       .start          = 0,
+       .end            = 0,
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device sdp_nor_device = {
+       .name           = "omapflash",
+       .id             = 0,
+       .dev            = {
+                       .platform_data = &sdp_nor_data,
+       },
+       .num_resources  = 1,
+       .resource       = &sdp_nor_resource,
+};
+
+static int sdp_onenand_setup(void __iomem *, int freq);
+
+static struct mtd_partition sdp_onenand_partitions[] = {
+       {
+               .name           = "X-Loader-OneNAND",
+               .offset         = 0,
+               .size           = 4 * (64 * 2048),
+               .mask_flags     = MTD_WRITEABLE  /* force read-only */
+       },
+       {
+               .name           = "U-Boot-OneNAND",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 2 * (64 * 2048),
+               .mask_flags     = MTD_WRITEABLE  /* force read-only */
+       },
+       {
+               .name           = "U-Boot Environment-OneNAND",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1 * (64 * 2048),
+       },
+       {
+               .name           = "Kernel-OneNAND",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 16 * (64 * 2048),
+       },
+       {
+               .name           = "File System-OneNAND",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data sdp_onenand_data = {
+       .parts          = sdp_onenand_partitions,
+       .nr_parts       = ARRAY_SIZE(sdp_onenand_partitions),
+       .onenand_setup  = sdp_onenand_setup,
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device sdp_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &sdp_onenand_data,
+       },
+};
+
+/*
+ * sdp_onenand_setup - The function configures the onenand flash.
+ * @onenand_base: Onenand base address
+ *
+ * @return int:        Currently always returning zero.
+ */
+static int sdp_onenand_setup(void __iomem *onenand_base, int freq)
+{
+       /* Onenand setup does nothing at present */
+       return 0;
+}
+
+static struct mtd_partition sdp_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+               .name           = "X-Loader-NAND",
+               .offset         = 0,
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "Boot Env-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x100000 */
+               .size           = 2 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "Kernel-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x140000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "File System - NAND",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x540000 */
+       },
+};
+
+static struct omap_nand_platform_data sdp_nand_data = {
+       .parts          = sdp_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(sdp_nand_partitions),
+       .nand_setup     = NULL,
+       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
+       .dev_ready      = NULL,
+};
+
+static struct resource sdp_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device sdp_nand_device = {
+       .name           = "omap2-nand",
+       .id             = 0,
+       .dev            = {
+       .platform_data  = &sdp_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &sdp_nand_resource,
+};
+
+
+/**
+ * sdp3430_flash_init - Identify devices connected to GPMC and register.
+ *
+ * @return - void.
+ */
+void __init sdp3430_flash_init(void)
+{
+       u8              cs = 0;
+       u8              nandcs = GPMC_CS_NUM + 1;
+       u8              onenandcs = GPMC_CS_NUM + 1;
+       unsigned long   gpmc_base_add;
+
+       gpmc_base_add   = OMAP34XX_GPMC_VIRT;
+
+       /* Configure start address and size of NOR device */
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               sdp_nor_resource.start  = FLASH_BASE_SDPV2;
+               sdp_nor_resource.end    = FLASH_BASE_SDPV2
+                                               + FLASH_SIZE_SDPV2 - 1;
+       } else {
+               sdp_nor_resource.start  = FLASH_BASE_SDPV1;
+               sdp_nor_resource.end    = FLASH_BASE_SDPV1
+                                               + FLASH_SIZE_SDPV1 - 1;
+       }
+
+       if (platform_device_register(&sdp_nor_device) < 0)
+               printk(KERN_ERR "Unable to register NOR device\n");
+
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               /*
+               * xloader/Uboot would have programmed the NAND/oneNAND
+               * base address for us This is a ugly hack. The proper
+               * way of doing this is to pass the setup of u-boot up
+               * to kernel using kernel params - something on the
+               * lines of machineID. Check if oneNAND is configured
+               */
+               if ((ret & 0xC00) == 0x800) {
+                       /* Found it!! */
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               } else {
+                       ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+                       if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+                       onenandcs = cs;
+               }
+               cs++;
+       }
+       if ((nandcs > GPMC_CS_NUM) && (onenandcs > GPMC_CS_NUM)) {
+               printk(KERN_INFO "NAND/OneNAND: Unable to find configuration "
+                               " in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               sdp_nand_data.cs        = nandcs;
+               sdp_nand_data.gpmc_cs_baseaddr   = (void *)(gpmc_base_add +
+                                       GPMC_CS0_BASE + nandcs*GPMC_CS_SIZE);
+               sdp_nand_data.gpmc_baseaddr     = (void *) (gpmc_base_add);
+
+               if (platform_device_register(&sdp_nand_device) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+
+       if (onenandcs < GPMC_CS_NUM) {
+               sdp_onenand_data.cs = onenandcs;
+               if (platform_device_register(&sdp_onenand_device) < 0)
+                       printk(KERN_ERR "Unable to register OneNAND device\n");
+       }
+}
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
new file mode 100644 (file)
index 0000000..56f28ae
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * linux/arch/arm/mach-omap2/board-3430sdp.c
+ *
+ * Copyright (C) 2007 Texas Instruments
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
+#include <mach/hsmmc.h>
+#include <mach/common.h>
+#include <mach/keypad.h>
+#include <mach/dma.h>
+#include <mach/gpmc.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+#include "sdram-qimonda-hyb18m512160af-6.h"
+
+#define        SDP3430_SMC91X_CS       3
+
+#define ENABLE_VAUX3_DEDICATED 0x03
+#define ENABLE_VAUX3_DEV_GRP   0x20
+
+
+#define TWL4030_MSECURE_GPIO 22
+
+static struct resource sdp3430_smc91x_resources[] = {
+       [0] = {
+               .start  = OMAP34XX_ETHR_START,
+               .end    = OMAP34XX_ETHR_START + SZ_4K,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = 0,
+               .end    = 0,
+               .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+       },
+};
+
+static struct platform_device sdp3430_smc91x_device = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sdp3430_smc91x_resources),
+       .resource       = sdp3430_smc91x_resources,
+};
+
+static int sdp3430_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(0, 4, KEY_C),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(1, 4, KEY_G),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(2, 4, KEY_3),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P),
+       KEY(3, 4, KEY_Q),
+       KEY(4, 0, KEY_R),
+       KEY(4, 1, KEY_4),
+       KEY(4, 2, KEY_T),
+       KEY(4, 3, KEY_U),
+       KEY(4, 4, KEY_D),
+       KEY(5, 0, KEY_V),
+       KEY(5, 1, KEY_W),
+       KEY(5, 2, KEY_L),
+       KEY(5, 3, KEY_S),
+       KEY(5, 4, KEY_H),
+       0
+};
+
+static struct twl4030_keypad_data sdp3430_kp_data = {
+       .rows           = 5,
+       .cols           = 6,
+       .keymap         = sdp3430_keymap,
+       .keymapsize     = ARRAY_SIZE(sdp3430_keymap),
+       .rep            = 1,
+       .irq            = TWL4030_MODIRQ_KEYPAD,
+};
+
+static int ts_gpio;
+
+static int __init msecure_init(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+       /* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+       if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+                       system_rev < OMAP3430_REV_ES2_0) {
+               u32 msecure_pad_config_reg = omap_ctrl_base_get() + 0xA3C;
+               int mux_mask = 0x04;
+               u16 tmp;
+
+               ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+               if (ret < 0) {
+                       printk(KERN_ERR "msecure_init: can't"
+                               "reserve GPIO:%d !\n", TWL4030_MSECURE_GPIO);
+                       goto out;
+               }
+               /*
+                * TWL4030 will be in secure mode if msecure line from OMAP
+                * is low. Make msecure line high in order to change the
+                * TWL4030 RTC time and calender registers.
+                */
+               tmp = omap_readw(msecure_pad_config_reg);
+               tmp &= 0xF8; /* To enable mux mode 03/04 = GPIO_RTC */
+               tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+               omap_writew(tmp, msecure_pad_config_reg);
+
+               gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+       }
+out:
+#endif
+       return ret;
+}
+
+/**
+ * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
+ *
+ * @return - void. If request gpio fails then Flag KERN_ERR.
+ */
+static void ads7846_dev_init(void)
+{
+       if (omap_request_gpio(ts_gpio) < 0) {
+               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+               return;
+       }
+
+       omap_set_gpio_direction(ts_gpio, 1);
+
+       omap_set_gpio_debounce(ts_gpio, 1);
+       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(ts_gpio);
+}
+
+/*
+ * This enable(1)/disable(0) the voltage for TS: uses twl4030 calls
+ */
+static int ads7846_vaux_control(int vaux_cntrl)
+{
+       int ret = 0;
+
+#ifdef CONFIG_TWL4030_CORE
+       /* check for return value of ldo_use: if success it returns 0 */
+       if (vaux_cntrl == VAUX_ENABLE) {
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       ENABLE_VAUX3_DEDICATED, TWL4030_VAUX3_DEDICATED))
+                       return -EIO;
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       ENABLE_VAUX3_DEV_GRP, TWL4030_VAUX3_DEV_GRP))
+                       return -EIO;
+       } else if (vaux_cntrl == VAUX_DISABLE) {
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       0x00, TWL4030_VAUX3_DEDICATED))
+                       return -EIO;
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       0x00, TWL4030_VAUX3_DEV_GRP))
+                       return -EIO;
+       }
+#else
+       ret = -EIO;
+#endif
+       return ret;
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+       .get_pendown_state      = ads7846_get_pendown_state,
+       .keep_vref_on           = 1,
+       .vaux_control           = ads7846_vaux_control,
+};
+
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,  /* 0: slave, 1: master */
+};
+
+static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
+       [0] = {
+               /*
+                * TSC2046 operates at a max freqency of 2MHz, so
+                * operate slightly below at 1.5MHz
+                */
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &tsc2046_mcspi_config,
+               .irq                    = 0,
+               .platform_data          = &tsc2046_config,
+       },
+};
+
+static struct platform_device sdp3430_lcd_device = {
+       .name           = "sdp2430_lcd",
+       .id             = -1,
+};
+
+static struct platform_device *sdp3430_devices[] __initdata = {
+       &sdp3430_smc91x_device,
+       &sdp3430_lcd_device,
+};
+
+static inline void __init sdp3430_init_smc91x(void)
+{
+       int eth_cs;
+       unsigned long cs_mem_base;
+       int eth_gpio = 0;
+
+       eth_cs = SDP3430_SMC91X_CS;
+
+       if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
+               return;
+       }
+
+       sdp3430_smc91x_resources[0].start = cs_mem_base + 0x0;
+       sdp3430_smc91x_resources[0].end   = cs_mem_base + 0xf;
+       udelay(100);
+
+       if (system_rev > OMAP3430_REV_ES1_0)
+               eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV2;
+       else
+               eth_gpio = OMAP34XX_ETHR_GPIO_IRQ_SDPV1;
+
+       sdp3430_smc91x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+       if (omap_request_gpio(eth_gpio) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
+                       eth_gpio);
+               return;
+       }
+       omap_set_gpio_direction(eth_gpio, 1);
+}
+
+static void __init omap_3430sdp_init_irq(void)
+{
+       omap2_init_common_hw(hyb18m512160af6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+       sdp3430_init_smc91x();
+}
+
+static struct omap_uart_config sdp3430_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_lcd_config sdp3430_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel sdp3430_config[] __initdata = {
+       { OMAP_TAG_UART,        &sdp3430_uart_config },
+       { OMAP_TAG_LCD,         &sdp3430_lcd_config },
+};
+
+static int sdp3430_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630,   9280,   8950,   8620,   8310,
+8020,   7730,   7460,   7200,   6950,   6710,   6470,   6250,   6040,   5830,
+5640,   5450,   5260,   5090,   4920,   4760,   4600,   4450,   4310,   4170,
+4040,   3910,   3790,   3670,   3550
+};
+
+static struct twl4030_bci_platform_data sdp3430_bci_data = {
+      .battery_tmp_tbl = sdp3430_batt_table,
+      .tblsize         = ARRAY_SIZE(sdp3430_batt_table),
+};
+
+static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data sdp3430_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data sdp3430_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data sdp3430_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .bci            = &sdp3430_bci_data,
+       .gpio           = &sdp3430_gpio_data,
+       .madc           = &sdp3430_madc_data,
+       .keypad         = &sdp3430_kp_data,
+       .usb            = &sdp3430_usb_data,
+};
+
+static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &sdp3430_twldata,
+       },
+};
+
+static int __init omap3430_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
+                       ARRAY_SIZE(sdp3430_i2c_boardinfo));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+extern void __init sdp3430_flash_init(void);
+
+static void __init omap_3430sdp_init(void)
+{
+       omap3430_i2c_init();
+       platform_add_devices(sdp3430_devices, ARRAY_SIZE(sdp3430_devices));
+       omap_board_config = sdp3430_config;
+       omap_board_config_size = ARRAY_SIZE(sdp3430_config);
+       if (system_rev > OMAP3430_REV_ES1_0)
+               ts_gpio = OMAP34XX_TS_GPIO_IRQ_SDPV2;
+       else
+               ts_gpio = OMAP34XX_TS_GPIO_IRQ_SDPV1;
+       sdp3430_spi_board_info[0].irq = OMAP_GPIO_IRQ(ts_gpio);
+       spi_register_board_info(sdp3430_spi_board_info,
+                               ARRAY_SIZE(sdp3430_spi_board_info));
+       ads7846_dev_init();
+       sdp3430_flash_init();
+       msecure_init();
+       omap_serial_init();
+       usb_musb_init();
+       usb_ehci_init();
+       hsmmc_init();
+}
+
+static void __init omap_3430sdp_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
+       /* Maintainer: Syed Khasim - Texas Instruments Inc */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_3430sdp_map_io,
+       .init_irq       = omap_3430sdp_init_irq,
+       .init_machine   = omap_3430sdp_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-apollon-keys.c b/arch/arm/mach-omap2/board-apollon-keys.c
new file mode 100644 (file)
index 0000000..e3f74e6
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/arm/mach-omap2/board-apollon-keys.c
+ *
+ * Copyright (C) 2007 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+
+#define SW_ENTER_GPIO16                16
+#define SW_UP_GPIO17           17
+#define SW_DOWN_GPIO58         58
+#define SW_LEFT_GPIO95         95
+#define SW_RIGHT_GPIO96                96
+#define SW_ESC_GPIO97          97
+
+static struct gpio_keys_button apollon_gpio_keys_buttons[] = {
+       [0] = {
+               .code           = KEY_ENTER,
+               .gpio           = SW_ENTER_GPIO16,
+               .desc           = "enter sw",
+       },
+       [1] = {
+               .code           = KEY_UP,
+               .gpio           = SW_UP_GPIO17,
+               .desc           = "up sw",
+       },
+       [2] = {
+               .code           = KEY_DOWN,
+               .gpio           = SW_DOWN_GPIO58,
+               .desc           = "down sw",
+       },
+       [3] = {
+               .code           = KEY_LEFT,
+               .gpio           = SW_LEFT_GPIO95,
+               .desc           = "left sw",
+       },
+       [4] = {
+               .code           = KEY_RIGHT,
+               .gpio           = SW_RIGHT_GPIO96,
+               .desc           = "right sw",
+       },
+       [5] = {
+               .code           = KEY_ESC,
+               .gpio           = SW_ESC_GPIO97,
+               .desc           = "esc sw",
+       },
+};
+
+static struct gpio_keys_platform_data apollon_gpio_keys = {
+       .buttons                = apollon_gpio_keys_buttons,
+       .nbuttons               = ARRAY_SIZE(apollon_gpio_keys_buttons),
+};
+
+static struct platform_device apollon_gpio_keys_device = {
+       .name                   = "gpio-keys",
+       .id                     = -1,
+       .dev                    = {
+               .platform_data  = &apollon_gpio_keys,
+       },
+};
+
+static void __init apollon_sw_init(void)
+{
+       /* Enter SW - Y11 */
+       omap_cfg_reg(Y11_242X_GPIO16);
+       /* Up SW - AA12 */
+       omap_cfg_reg(AA12_242X_GPIO17);
+       /* Down SW - AA8 */
+       omap_cfg_reg(AA8_242X_GPIO58);
+
+       if (apollon_plus()) {
+               /* Left SW - P18 */
+               omap_cfg_reg(P18_24XX_GPIO95);
+               /* Right SW - M18 */
+               omap_cfg_reg(M18_24XX_GPIO96);
+               /* Esc SW - L14 */
+               omap_cfg_reg(L14_24XX_GPIO97);
+       } else
+               apollon_gpio_keys.nbuttons = 3;
+}
+
+static int __init omap_apollon_keys_init(void)
+{
+       apollon_sw_init();
+
+       return platform_device_register(&apollon_gpio_keys_device);
+}
+
+arch_initcall(omap_apollon_keys_init);
diff --git a/arch/arm/mach-omap2/board-apollon-mmc.c b/arch/arm/mach-omap2/board-apollon-mmc.c
new file mode 100644 (file)
index 0000000..35c2c07
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/arm/mach-omap2/board-apollon-mmc.c
+ *
+ * Copyright (C) 2005-2007 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/mmc.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+static struct device *mmc_device;
+
+static int apollon_mmc_set_power(struct device *dev, int slot, int power_on,
+                                       int vdd)
+{
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+               power_on ? "on" : "off", vdd);
+#endif
+       if (slot != 0) {
+               dev_err(dev, "No such slot %d\n", slot + 1);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int apollon_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d bus_mode %s\n", slot + 1,
+               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+#endif
+       if (slot != 0) {
+               dev_err(dev, "No such slot %d\n", slot + 1);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int apollon_mmc_late_init(struct device *dev)
+{
+       mmc_device = dev;
+
+       return 0;
+}
+
+static void apollon_mmc_cleanup(struct device *dev)
+{
+}
+
+/*
+ * Note: If you want to detect card feature, please assign GPIO 37
+ */
+static struct omap_mmc_platform_data mmc1_data = {
+       .nr_slots                       = 1,
+       .init                           = apollon_mmc_late_init,
+       .cleanup                        = apollon_mmc_cleanup,
+       .dma_mask                       = 0xffffffff,
+       .slots[0]       = {
+               .wire4                  = 1,
+
+               /*
+                * Use internal loop-back in MMC/SDIO Module Input Clock
+                * selection
+                */
+               .internal_clock         = 1,
+
+               .set_power              = apollon_mmc_set_power,
+               .set_bus_mode           = apollon_mmc_set_bus_mode,
+               .ocr_mask               = MMC_VDD_30_31 | MMC_VDD_31_32 |
+                                         MMC_VDD_32_33 | MMC_VDD_33_34,
+               .name                   = "mmcblk",
+       },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init apollon_mmc_init(void)
+{
+       mmc_data[0] = &mmc1_data;
+       omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+
+#else  /* !CONFIG_MMC_OMAP */
+
+void __init apollon_mmc_init(void)
+{
+}
+
+#endif /* CONFIG_MMC_OMAP */
index 989ad152d7f87105c6b02a1ea4bf0c7fdbc3cd00..1f3af4825e7f1b85ea1ac9e59b41a34e3e644502 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * linux/arch/arm/mach-omap2/board-apollon.c
  *
- * Copyright (C) 2005,2006 Samsung Electronics
+ * Copyright (C) 2005-2008 Samsung Electronics
  * Author: Kyungmin Park <kyungmin.park@samsung.com>
  *
- * Modified from mach-omap/omap2/board-h4.c
+ * Modified from mach-omap2/board-h4.c
  *
  * Code for apollon OMAP2 board. Should work on many OMAP2 systems where
  * the bootloader passes the board-specific data to the kernel.
 #include <linux/leds.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
 
+#include <asm/io.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/board.h>
 #include <mach/common.h>
 #include <mach/gpmc.h>
-#include <mach/control.h>
 
 /* LED & Switch macros */
 #define LED0_GPIO13            13
 #define LED1_GPIO14            14
 #define LED2_GPIO15            15
-#define SW_ENTER_GPIO16                16
-#define SW_UP_GPIO17           17
-#define SW_DOWN_GPIO58         58
+#define LED3_GPIO92            92
+#define LED4_GPIO93            93
 
 #define APOLLON_FLASH_CS       0
 #define APOLLON_ETH_CS         1
+#define APOLLON_NOR_CS         3
+
+#define APOLLON_ONENAND_CS2_ADDRESS    (0x00000e40 | (0x10000000 >> 24))
+#define APOLLON_EXT_CS3_ADDRESS                (0x00000c40 | (0x18000000 >> 24))
 
 static struct mtd_partition apollon_partitions[] = {
        {
@@ -109,6 +114,63 @@ static struct platform_device apollon_onenand_device = {
        .resource       = apollon_flash_resource,
 };
 
+static struct mtd_partition apollon_nor_partitions[] = {
+       {
+               .name           = "U-Boot",
+               .offset         = 0,
+               .size           = SZ_128K,
+               .mask_flags     = MTD_WRITEABLE,
+       },
+       {
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_128K,
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_2M,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_4M - SZ_256K,
+       },
+       {
+               .name           = "application",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = SZ_8M + SZ_2M,
+       },
+       {
+               .name           = "reserved",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct flash_platform_data apollon_nor_data = {
+       .map_name               = "cfi_probe",
+       .width          = 2,
+       .parts          = apollon_nor_partitions,
+       .nr_parts       = ARRAY_SIZE(apollon_nor_partitions),
+};
+
+static struct resource apollon_nor_resource[] = {
+       [0] = {
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device apollon_nor_device = {
+       .name           = "omapflash",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &apollon_nor_data,
+       },
+       .num_resources  = ARRAY_SIZE(apollon_nor_resource),
+       .resource       = apollon_nor_resource,
+};
+
 static void __init apollon_flash_init(void)
 {
        unsigned long base;
@@ -119,6 +181,13 @@ static void __init apollon_flash_init(void)
        }
        apollon_flash_resource[0].start = base;
        apollon_flash_resource[0].end   = base + SZ_128K - 1;
+
+       if (gpmc_cs_request(APOLLON_NOR_CS, SZ_32M, &base) < 0) {
+               printk(KERN_ERR "Cannot request NOR GPMC CS\n");
+               return;
+       }
+       apollon_nor_resource[0].start = base;
+       apollon_nor_resource[0].end   = base + SZ_32M - 1;
 }
 
 static struct resource apollon_smc91x_resources[] = {
@@ -144,34 +213,37 @@ static struct platform_device apollon_lcd_device = {
        .id             = -1,
 };
 
-static struct omap_led_config apollon_led_config[] = {
+static struct gpio_led apollon_led_config[] = {
+       {
+               .name                   = "d2",
+               .gpio                   = LED0_GPIO13,
+               .default_trigger        = "heartbeat",
+       },
        {
-               .cdev   = {
-                       .name   = "apollon:led0",
-               },
-               .gpio   = LED0_GPIO13,
+               .name                   = "d3",
+               .gpio                   = LED1_GPIO14,
        },
        {
-               .cdev   = {
-                       .name   = "apollon:led1",
-               },
-               .gpio   = LED1_GPIO14,
+               .name                   = "d4",
+               .gpio                   = LED2_GPIO15,
        },
        {
-               .cdev   = {
-                       .name   = "apollon:led2",
-               },
-               .gpio   = LED2_GPIO15,
+               .name                   = "d5",
+               .gpio                   = LED3_GPIO92,
+       },
+       {
+               .name                   = "d6",
+               .gpio                   = LED4_GPIO93,
        },
 };
 
-static struct omap_led_platform_data apollon_led_data = {
-       .nr_leds        = ARRAY_SIZE(apollon_led_config),
+static struct gpio_led_platform_data apollon_led_data = {
+       .num_leds       = ARRAY_SIZE(apollon_led_config),
        .leds           = apollon_led_config,
 };
 
 static struct platform_device apollon_led_device = {
-       .name           = "omap-led",
+       .name           = "leds-gpio",
        .id             = -1,
        .dev            = {
                .platform_data  = &apollon_led_data,
@@ -180,6 +252,7 @@ static struct platform_device apollon_led_device = {
 
 static struct platform_device *apollon_devices[] __initdata = {
        &apollon_onenand_device,
+       &apollon_nor_device,
        &apollon_smc91x_device,
        &apollon_lcd_device,
        &apollon_led_device,
@@ -188,7 +261,6 @@ static struct platform_device *apollon_devices[] __initdata = {
 static inline void __init apollon_init_smc91x(void)
 {
        unsigned long base;
-
        unsigned int rate;
        struct clk *gpmc_fck;
        int eth_cs;
@@ -227,7 +299,7 @@ static inline void __init apollon_init_smc91x(void)
                gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
        }
 
-       if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) {
+       if (gpmc_cs_request(eth_cs, SZ_16M, &base) < 0) {
                printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
                goto out;
        }
@@ -239,7 +311,7 @@ static inline void __init apollon_init_smc91x(void)
        if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) {
                printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
                        APOLLON_ETHR_GPIO_IRQ);
-               gpmc_cs_free(APOLLON_ETH_CS);
+               gpmc_cs_free(eth_cs);
                goto out;
        }
        omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
@@ -251,26 +323,34 @@ out:
 
 static void __init omap_apollon_init_irq(void)
 {
-       omap2_init_common_hw();
+       omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
        apollon_init_smc91x();
 }
 
-static struct omap_uart_config apollon_uart_config __initdata = {
-       .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
+static struct tsc210x_config tsc_platform_data = {
+       .use_internal           = 1,
+       .monitor                = TSC_TEMP,
+       .mclk                   = "sys_clkout",
 };
 
-static struct omap_mmc_config apollon_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
+static struct spi_board_info apollon_spi_board_info[] = {
+       [0] = {
+               .modalias       = "tsc2101",
+               .irq            = OMAP_GPIO_IRQ(85),
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_1,
+               .max_speed_hz   = 6000000,
+               .platform_data  = &tsc_platform_data,
        },
 };
 
+static struct omap_uart_config apollon_uart_config __initdata = {
+       .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2),
+};
+
 static struct omap_usb_config apollon_usb_config __initdata = {
        .register_dev   = 1,
        .hmc_mode       = 0x14, /* 0:dev 1:host1 2:disable */
@@ -282,9 +362,8 @@ static struct omap_lcd_config apollon_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
-static struct omap_board_config_kernel apollon_config[] = {
+static struct omap_board_config_kernel apollon_config[] __initdata = {
        { OMAP_TAG_UART,        &apollon_uart_config },
-       { OMAP_TAG_MMC,         &apollon_mmc_config },
        { OMAP_TAG_USB,         &apollon_usb_config },
        { OMAP_TAG_LCD,         &apollon_lcd_config },
 };
@@ -293,65 +372,18 @@ static void __init apollon_led_init(void)
 {
        /* LED0 - AA10 */
        omap_cfg_reg(AA10_242X_GPIO13);
-       omap_request_gpio(LED0_GPIO13);
-       omap_set_gpio_direction(LED0_GPIO13, 0);
-       omap_set_gpio_dataout(LED0_GPIO13, 0);
        /* LED1  - AA6 */
        omap_cfg_reg(AA6_242X_GPIO14);
-       omap_request_gpio(LED1_GPIO14);
-       omap_set_gpio_direction(LED1_GPIO14, 0);
-       omap_set_gpio_dataout(LED1_GPIO14, 0);
        /* LED2  - AA4 */
        omap_cfg_reg(AA4_242X_GPIO15);
-       omap_request_gpio(LED2_GPIO15);
-       omap_set_gpio_direction(LED2_GPIO15, 0);
-       omap_set_gpio_dataout(LED2_GPIO15, 0);
-}
 
-static irqreturn_t apollon_sw_interrupt(int irq, void *ignored)
-{
-       static unsigned int led0, led1, led2;
-
-       if (irq == OMAP_GPIO_IRQ(SW_ENTER_GPIO16))
-               omap_set_gpio_dataout(LED0_GPIO13, led0 ^= 1);
-       else if (irq == OMAP_GPIO_IRQ(SW_UP_GPIO17))
-               omap_set_gpio_dataout(LED1_GPIO14, led1 ^= 1);
-       else if (irq == OMAP_GPIO_IRQ(SW_DOWN_GPIO58))
-               omap_set_gpio_dataout(LED2_GPIO15, led2 ^= 1);
-
-       return IRQ_HANDLED;
-}
-
-static void __init apollon_sw_init(void)
-{
-       /* Enter SW - Y11 */
-       omap_cfg_reg(Y11_242X_GPIO16);
-       omap_request_gpio(SW_ENTER_GPIO16);
-       omap_set_gpio_direction(SW_ENTER_GPIO16, 1);
-       /* Up SW - AA12 */
-       omap_cfg_reg(AA12_242X_GPIO17);
-       omap_request_gpio(SW_UP_GPIO17);
-       omap_set_gpio_direction(SW_UP_GPIO17, 1);
-       /* Down SW - AA8 */
-       omap_cfg_reg(AA8_242X_GPIO58);
-       omap_request_gpio(SW_DOWN_GPIO58);
-       omap_set_gpio_direction(SW_DOWN_GPIO58, 1);
-
-       set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQ_TYPE_EDGE_RISING);
-       if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt,
-                               IRQF_SHARED, "enter sw",
-                               &apollon_sw_interrupt))
-               return;
-       set_irq_type(OMAP_GPIO_IRQ(SW_UP_GPIO17), IRQ_TYPE_EDGE_RISING);
-       if (request_irq(OMAP_GPIO_IRQ(SW_UP_GPIO17), &apollon_sw_interrupt,
-                               IRQF_SHARED, "up sw",
-                               &apollon_sw_interrupt))
-               return;
-       set_irq_type(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), IRQ_TYPE_EDGE_RISING);
-       if (request_irq(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), &apollon_sw_interrupt,
-                               IRQF_SHARED, "down sw",
-                               &apollon_sw_interrupt))
-               return;
+       if (apollon_plus()) {
+               /* LED3 - M15 */
+               omap_cfg_reg(M15_24XX_GPIO92);
+               /* LED4 - P20 */
+               omap_cfg_reg(P20_24XX_GPIO93);
+       } else
+               apollon_led_data.num_leds = 3;
 }
 
 static void __init apollon_usb_init(void)
@@ -364,22 +396,101 @@ static void __init apollon_usb_init(void)
        omap_set_gpio_dataout(12, 0);
 }
 
-static void __init omap_apollon_init(void)
+static void __init apollon_tsc_init(void)
 {
-       u32 v;
+       /* TSC2101 */
+       omap_cfg_reg(N15_24XX_GPIO85);
+       omap_request_gpio(85);
+       omap_set_gpio_direction(85, 1);
+
+       omap_cfg_reg(W14_24XX_SYS_CLKOUT);      /* mclk */
+}
 
+static void __init apollon_cs_init(void)
+{
+       unsigned long base;
+       unsigned int rate;
+       struct clk *l3ck;
+       u32 value;
+       int cs, sync = 0;
+
+       l3ck = clk_get(NULL, "core_l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       else
+               rate = clk_get_rate(l3ck);
+
+       /* CS2: OneNAND */
+       cs = 2;
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG1);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, value);
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG2);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, value);
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG3);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, value);
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG4);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, value);
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG5);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, value);
+       value = gpmc_cs_read_reg(0, GPMC_CS_CONFIG6);
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, value);
+
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, APOLLON_ONENAND_CS2_ADDRESS);
+
+       /* CS3: External NOR */
+       cs = APOLLON_NOR_CS;
+       if (rate >= 160000000) {
+               sync = 1;
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0xe5011211);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00090b01);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00020201);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x09030b03);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x010a0a0c);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+       } else if (rate >= 130000000) {
+               /* Not yet know ... Use the async values */
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0x00021201);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00121601);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00040401);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x12061605);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x01151317);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+       } else {/* rate = 100000000 */
+               sync = 1;
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, 0xe1001202);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, 0x00151501);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, 0x00050501);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, 0x0e070e07);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG5, 0x01131F1F);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, 0x00000000);
+       }
+
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, APOLLON_EXT_CS3_ADDRESS);
+
+       if (gpmc_cs_request(cs, SZ_32M, &base) < 0) {
+               printk(KERN_ERR "Failed to request GPMC CS for external\n");
+               return;
+       }
+
+       /* Synchronous mode */
+       if (sync) {
+               void __iomem *addr = ioremap(base, SZ_32M);
+               writew(0xaa, addr + 0xaaa);
+               writew(0x55, addr + 0x554);
+               writew(0xc0, addr + 0x24aaa);
+               iounmap(addr);
+       }
+
+       gpmc_cs_free(cs);
+}
+
+static void __init omap_apollon_init(void)
+{
+       apollon_cs_init();
        apollon_led_init();
-       apollon_sw_init();
        apollon_flash_init();
        apollon_usb_init();
-
-       /* REVISIT: where's the correct place */
-       omap_cfg_reg(W19_24XX_SYS_NIRQ);
-
-       /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
-       v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
-       v |= (1 << 24);
-       omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
+       apollon_tsc_init();
 
        /*
         * Make sure the serial ports are muxed on at this point.
@@ -390,6 +501,13 @@ static void __init omap_apollon_init(void)
        omap_board_config = apollon_config;
        omap_board_config_size = ARRAY_SIZE(apollon_config);
        omap_serial_init();
+       omap_register_i2c_bus(1, 100, NULL, 0);
+       omap_register_i2c_bus(2, 100, NULL, 0);
+
+       spi_register_board_info(apollon_spi_board_info,
+                               ARRAY_SIZE(apollon_spi_board_info));
+
+       apollon_mmc_init();
 }
 
 static void __init omap_apollon_map_io(void)
index 9ba097868e72b78657a3608ef79fef647276b166..0e353b3611f373503dbb6674e1ce15d85d606125 100644 (file)
@@ -33,7 +33,7 @@
 
 static void __init omap_generic_init_irq(void)
 {
-       omap2_init_common_hw();
+       omap2_init_common_hw(NULL);
        omap_init_irq();
 }
 
@@ -41,19 +41,8 @@ static struct omap_uart_config generic_uart_config __initdata = {
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
-static struct omap_mmc_config generic_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 0,
-               .wire4          = 0,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
-       },
-};
-
-static struct omap_board_config_kernel generic_config[] = {
+static struct omap_board_config_kernel generic_config[] __initdata = {
        { OMAP_TAG_UART,        &generic_uart_config },
-       { OMAP_TAG_MMC,         &generic_mmc_config },
 };
 
 static void __init omap_generic_init(void)
@@ -61,6 +50,8 @@ static void __init omap_generic_init(void)
        omap_board_config = generic_config;
        omap_board_config_size = ARRAY_SIZE(generic_config);
        omap_serial_init();
+       omap_register_i2c_bus(1, 100, NULL, 0);
+       omap_register_i2c_bus(2, 100, NULL, 0);
 }
 
 static void __init omap_generic_map_io(void)
diff --git a/arch/arm/mach-omap2/board-h4-mmc.c b/arch/arm/mach-omap2/board-h4-mmc.c
new file mode 100644 (file)
index 0000000..06119e9
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * linux/arch/arm/mach-omap2/board-h4-mmc.c
+ *
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ * Authors: David Cohen <david.cohen@indt.org.br>
+ *          Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
+ *
+ * This code is based on linux/arch/arm/mach-omap2/board-n800-mmc.c, which is:
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/menelaus.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/mmc.h>
+
+#ifdef CONFIG_MMC_OMAP
+
+/* Bit mask for slots detection interrupts */
+#define SD1_CD_ST      (1 << 0)
+#define SD2_CD_ST      (1 << 1)
+
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
+/*
+ * VMMC --> slot 1
+ * VDCDC3_APE, VMCS2_APE --> slot 2
+ */
+
+static int h4_mmc_switch_slot(struct device *dev, int slot)
+{
+       int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Choose slot %d\n", slot + 1);
+#endif
+       if (slot == 0) {
+               r = menelaus_enable_slot(2, 0);
+               r |= menelaus_enable_slot(1, 1);
+       } else {
+               r = menelaus_enable_slot(1, 0);
+               r |= menelaus_enable_slot(2, 1);
+       }
+
+       return r ? -ENODEV : 0;
+}
+
+static int h4_mmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       int mV = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+               power_on ? "on" : "off", vdd);
+#endif
+       if (slot == 0) {
+               if (!power_on)
+                       return menelaus_set_vmmc(3000);
+               switch (1 << vdd) {
+                       case MMC_VDD_33_34:
+                       case MMC_VDD_32_33:
+                       case MMC_VDD_31_32:
+                               mV = 3100;
+                               break;
+                       case MMC_VDD_30_31:
+                               mV = 3000;
+                               break;
+                       case MMC_VDD_28_29:
+                               mV = 2800;
+                               break;
+                       case MMC_VDD_165_195:
+                               mV = 1850;
+                               break;
+                       default:
+                               BUG();
+               }
+               return menelaus_set_vmmc(mV);
+       } else {
+               if (!power_on)
+                       return menelaus_set_vdcdc(3, 3000);
+               switch (1 << vdd) {
+                       case MMC_VDD_33_34:
+                       case MMC_VDD_32_33:
+                               mV = 3300;
+                               break;
+                       case MMC_VDD_30_31:
+                       case MMC_VDD_29_30:
+                               mV = 3000;
+                               break;
+                       case MMC_VDD_28_29:
+                       case MMC_VDD_27_28:
+                               mV = 2800;
+                               break;
+                       case MMC_VDD_24_25:
+                       case MMC_VDD_23_24:
+                               mV = 2400;
+                               break;
+                       case MMC_VDD_22_23:
+                       case MMC_VDD_21_22:
+                               mV = 2200;
+                               break;
+                       case MMC_VDD_20_21:
+                               mV = 2000;
+                               break;
+                       case MMC_VDD_165_195:
+                               mV = 1800;
+                               break;
+                       default:
+                               BUG();
+               }
+               return menelaus_set_vdcdc(3, mV);
+       }
+       return 0;
+}
+
+static int h4_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+       int r = 0;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
+               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+#endif
+       BUG_ON(slot != 0 && slot != 1);
+       slot++;
+       switch (bus_mode) {
+       case MMC_BUSMODE_OPENDRAIN:
+               r = menelaus_set_mmc_opendrain(slot, 1);
+               break;
+       case MMC_BUSMODE_PUSHPULL:
+               r = menelaus_set_mmc_opendrain(slot, 0);
+               break;
+       default:
+               BUG();
+       }
+       if (r != 0 && printk_ratelimit()) {
+               dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
+                       slot);
+       }
+       return r;
+}
+
+static int h4_mmc_slot1_cover_state(struct device *dev, int slot)
+{
+       BUG_ON(slot != 0);
+       return slot1_cover_open;
+}
+
+static int h4_mmc_slot2_cover_state(struct device *dev, int slot)
+{
+       BUG_ON(slot != 1);
+       return slot2_cover_open;
+}
+
+static void h4_mmc_slot_callback(void *data, u8 card_mask)
+{
+       int cover_open;
+
+       cover_open = (card_mask & SD1_CD_ST) ? 0 : 1;
+       if (cover_open != slot1_cover_open) {
+               slot1_cover_open = cover_open;
+               omap_mmc_notify_cover_event(mmc_device, 0, slot1_cover_open);
+       }
+
+       cover_open = (card_mask & SD2_CD_ST) ? 0 : 1;
+       if (cover_open != slot2_cover_open) {
+               slot2_cover_open = cover_open;
+               omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_open);
+       }
+}
+
+static int h4_mmc_late_init(struct device *dev)
+{
+       int r;
+
+       mmc_device = dev;
+
+       r = menelaus_set_mmc_slot(1, 0, 0, 1);
+       if (r < 0)
+               goto out;
+       r = menelaus_set_mmc_slot(2, 0, 0, 1);
+       if (r < 0)
+               goto out;
+
+       r = menelaus_get_slot_pin_states();
+       if (r < 0)
+               goto out;
+
+       if (r & SD1_CD_ST)
+               slot1_cover_open = 1;
+       else
+               slot1_cover_open = 0;
+
+       /* Slot pin bits seem to be inversed until first swith change,
+        * but just for slot 2
+        */
+       if ((r == 0xf) || (r == (0xf & ~SD2_CD_ST)))
+               r = ~r;
+
+       if (r & SD2_CD_ST)
+               slot2_cover_open = 1;
+       else
+               slot2_cover_open = 0;
+
+       r = menelaus_register_mmc_callback(h4_mmc_slot_callback, NULL);
+
+out:
+       return r;
+}
+
+static void h4_mmc_cleanup(struct device *dev)
+{
+       menelaus_unregister_mmc_callback();
+}
+
+static struct omap_mmc_platform_data mmc1_data = {
+       .nr_slots               = 2,
+       .switch_slot            = h4_mmc_switch_slot,
+       .init                   = h4_mmc_late_init,
+       .cleanup                = h4_mmc_cleanup,
+       .dma_mask               = 0xffffffff,
+       .slots[0] = {
+               .wire4          = 1,
+               .set_power      = h4_mmc_set_power,
+               .set_bus_mode   = h4_mmc_set_bus_mode,
+               .get_cover_state= h4_mmc_slot1_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 |
+                                 MMC_VDD_28_29 | MMC_VDD_30_31 |
+                                 MMC_VDD_32_33 | MMC_VDD_33_34,
+               .name           = "slot1",
+       },
+       .slots[1] = {
+               .wire4          = 1,
+               .set_power      = h4_mmc_set_power,
+               .set_bus_mode   = h4_mmc_set_bus_mode,
+               .get_cover_state= h4_mmc_slot2_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_20_21 |
+                                 MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+                                 MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+                                 MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+                                 MMC_VDD_33_34,
+               .name           = "slot2",
+       },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init h4_mmc_init(void)
+{
+       mmc_data[0] = &mmc1_data;
+       omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+
+#else
+
+void __init h4_mmc_init(void)
+{
+}
+
+#endif
+
index 9e2624ca70a2493cb0320d0373d446e91d1526da..733e134fb256b2fccb93b29280b57b71fce1f67a 100644 (file)
 #include <linux/input.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/i2c/menelaus.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+
+#include <media/v4l2-int-device.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <mach/board.h>
 #include <mach/common.h>
 #include <mach/keypad.h>
-#include <mach/menelaus.h>
 #include <mach/dma.h>
 #include <mach/gpmc.h>
 
 #include <asm/io.h>
 
+#include <../drivers/media/video/ov9640.h>
+
 #define H4_FLASH_CS    0
 #define H4_SMC91X_CS   1
 
@@ -137,6 +144,7 @@ static struct platform_device h4_flash_device = {
 
 /* 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;
@@ -196,6 +204,10 @@ static int h4_transceiver_mode(struct device *dev, int mode)
 
        return 0;
 }
+#else
+static int h4_select_irda(struct device *dev, int state) { return 0; }
+static int h4_transceiver_mode(struct device *dev, int mode) { return 0; }
+#endif
 
 static struct omap_irda_config h4_irda_data = {
        .transceiver_cap        = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE,
@@ -266,6 +278,8 @@ static u32 get_sysboot_value(void)
                 OMAP2_SYSBOOT_1_MASK | OMAP2_SYSBOOT_0_MASK));
 }
 
+/* FIXME: This function should be moved to some other file, gpmc.c? */
+
 /* H4-2420's always used muxed mode, H4-2422's always use non-muxed
  *
  * Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423
@@ -362,34 +376,277 @@ static void __init h4_init_flash(void)
 
 static void __init omap_h4_init_irq(void)
 {
-       omap2_init_common_hw();
+       omap2_init_common_hw(NULL);
        omap_init_irq();
        omap_gpio_init();
        h4_init_flash();
 }
 
 static struct omap_uart_config h4_uart_config __initdata = {
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+       .enabled_uarts = ((1 << 0) | (1 << 1)),
+#else
        .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
-};
-
-static struct omap_mmc_config h4_mmc_config __initdata = {
-       .mmc [0] = {
-               .enabled        = 1,
-               .wire4          = 1,
-               .wp_pin         = -1,
-               .power_pin      = -1,
-               .switch_pin     = -1,
-       },
+#endif
 };
 
 static struct omap_lcd_config h4_lcd_config __initdata = {
        .ctrl_name      = "internal",
 };
 
-static struct omap_board_config_kernel h4_config[] = {
+static struct omap_usb_config h4_usb_config __initdata = {
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+       /* NOTE:  usb1 could also be used with 3 wire signaling */
+       .pins[1]        = 4,
+#endif
+
+#ifdef CONFIG_MACH_OMAP_H4_OTG
+       /* S1.10 ON -- USB OTG port
+        * usb0 switched to Mini-AB port and isp1301 transceiver;
+        * S2.POS3 = OFF, S2.POS4 = ON ... to allow battery charging
+        */
+       .otg            = 1,
+       .pins[0]        = 4,
+#ifdef CONFIG_USB_GADGET_OMAP
+       /* use OTG cable, or standard A-to-MiniB */
+       .hmc_mode       = 0x14, /* 0:dev/otg 1:host 2:disable */
+#elif  defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+       /* use OTG cable, or NONSTANDARD (B-to-MiniB) */
+       .hmc_mode       = 0x11, /* 0:host 1:host 2:disable */
+#endif /* XX */
+
+#else
+       /* S1.10 OFF -- usb "download port"
+        * usb0 switched to Mini-B port and isp1105 transceiver;
+        * S2.POS3 = ON, S2.POS4 = OFF ... to enable battery charging
+        */
+       .register_dev   = 1,
+       .pins[0]        = 3,
+/*     .hmc_mode       = 0x14,*/       /* 0:dev 1:host 2:disable */
+       .hmc_mode       = 0x00,         /* 0:dev|otg 1:disable 2:disable */
+#endif
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct tsc210x_config tsc_platform_data = {
+       .use_internal           = 1,
+       .monitor                = TSC_VBAT | TSC_TEMP,
+       /* REVISIT temp calibration data -- board-specific; from EEPROM? */
+       .mclk                   = "sys_clkout",
+};
+
+static struct spi_board_info h4_spi_board_info[] __initdata = {
+       {
+               .modalias       = "tsc2101",
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .mode           = SPI_MODE_1,
+               .irq            = OMAP_GPIO_IRQ(93),
+               .max_speed_hz   = 16000000,
+               .platform_data  = &tsc_platform_data,
+       },
+
+       /* nCS1 -- to lcd board, but unused
+        * nCS2 -- to WLAN/miniPCI
+        */
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct omap_board_config_kernel h4_config[] __initdata = {
        { OMAP_TAG_UART,        &h4_uart_config },
-       { OMAP_TAG_MMC,         &h4_mmc_config },
        { OMAP_TAG_LCD,         &h4_lcd_config },
+       { OMAP_TAG_USB,         &h4_usb_config },
+};
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+
+#include <linux/usb/musb.h>
+
+static struct musb_hdrc_platform_data tusb_data = {
+       .mode           = MUSB_OTG,
+       .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+
+       /* 1.8V supplied by Menelaus, other voltages supplied by VBAT;
+        * so no switching.
+        */
+};
+
+static void __init tusb_evm_setup(void)
+{
+       static char     announce[] __initdata =
+                               KERN_INFO "TUSB 6010 EVM\n";
+       int             irq;
+       unsigned        dmachan = 0;
+
+       /* There are at least 32 different combinations of boards that
+        * are loosely called "H4", with a 2420 ... different OMAP chip
+        * revisions (with pin mux changes for DMAREQ, GPMC errata, etc),
+        * modifications of the CPU board, mainboard, EVM, TUSB etc.
+        * Plus omap2422, omap2423, etc.
+        *
+        * So you might need to tweak this setup to make the TUSB EVM
+        * behave on your particular setup ...
+        */
+
+       /* Already set up:  GPMC AD[0..15], CLK, nOE, nWE, nADV_ALE */
+       omap_cfg_reg(E2_GPMC_NCS2);
+       omap_cfg_reg(L2_GPMC_NCS7);
+       omap_cfg_reg(M1_GPMC_WAIT2);
+
+       switch ((system_rev >> 8) & 0x0f) {
+       case 0:         /* ES 1.0 */
+       case 1:         /* ES 2.0 */
+               /* Assume early board revision without optional ES2.0
+                * rework to swap J15 & AA10 so DMAREQ0 works
+                */
+               omap_cfg_reg(AA10_242X_GPIO13);
+               irq = 13;
+               /* omap_cfg_reg(J15_24XX_DMAREQ0); */
+               break;
+       default:
+               /* Later Menelaus boards can support all 6 DMA request
+                * lines, at the price of boot flash A23-A26.
+                */
+               omap_cfg_reg(J15_24XX_GPIO99);
+               irq = 99;
+               dmachan = (1 << 1) | (1 << 0);
+#if !(defined(CONFIG_MTD_OMAP_NOR) || defined(CONFIG_MTD_OMAP_NOR_MODULE))
+               dmachan |= (1 << 5) | (1 << 4) (1 << 3) | (1 << 2);
+#endif
+               break;
+       }
+
+       if (tusb6010_setup_interface(&tusb_data,
+                       TUSB6010_REFCLK_24, /* waitpin */ 2,
+                       /* async cs */ 2, /* sync cs */ 7,
+                       irq, dmachan) == 0)
+               printk(announce);
+}
+
+#endif
+
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+/*
+ * Common OV9640 register initialization for all image sizes, pixel formats,
+ * and frame rates
+ */
+const static struct ov9640_reg ov9640_common[] = {
+       { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x8F }, /* COM7, CLKRC, COM8 */
+       { 0x01, 0x80 }, { 0x02, 0x80 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */
+       { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0x4A }, /* COM5, COM6, COM9 */
+       { 0x16, 0x02 }, { 0x1B, 0x01 }, { 0x24, 0x70 }, /* ?, PSHFT, AEW */
+       { 0x25, 0x68 }, { 0x26, 0xD3 }, { 0x27, 0x90 }, /* AEB, VPT, BBIAS */
+       { 0x2A, 0x00 }, { 0x2B, 0x00 }, { 0x32, 0x24 }, /* EXHCH, EXHCL, HREF */
+       { 0x33, 0x02 }, { 0x37, 0x02 }, { 0x38, 0x13 }, /* CHLF, ADC, ACOM */
+       { 0x39, 0xF0 }, { 0x3A, 0x00 }, { 0x3B, 0x01 }, /* OFON, TSLB, COM11 */
+       { 0x3D, 0x90 }, { 0x3E, 0x02 }, { 0x3F, 0xF2 }, /* COM13, COM14, EDGE */
+       { 0x41, 0x02 }, { 0x42, 0xC8 },         /* COM16, COM17 */
+       { 0x43, 0xF0 }, { 0x44, 0x10 }, { 0x45, 0x6C }, /* ?, ?, ? */
+       { 0x46, 0x6C }, { 0x47, 0x44 }, { 0x48, 0x44 }, /* ?, ?, ? */
+       { 0x49, 0x03 }, { 0x59, 0x49 }, { 0x5A, 0x94 }, /* ?, ?, ? */
+       { 0x5B, 0x46 }, { 0x5C, 0x84 }, { 0x5D, 0x5C }, /* ?, ?, ? */
+       { 0x5E, 0x08 }, { 0x5F, 0x00 }, { 0x60, 0x14 }, /* ?, ?, ? */
+       { 0x61, 0xCE },                                 /* ? */
+       { 0x62, 0x70 }, { 0x63, 0x00 }, { 0x64, 0x04 }, /* LCC1, LCC2, LCC3 */
+       { 0x65, 0x00 }, { 0x66, 0x00 },                 /* LCC4, LCC5 */
+       { 0x69, 0x00 }, { 0x6A, 0x3E }, { 0x6B, 0x3F }, /* HV, MBD, DBLV */
+       { 0x6C, 0x40 }, { 0x6D, 0x30 }, { 0x6E, 0x4B }, /* GSP1, GSP2, GSP3 */
+       { 0x6F, 0x60 }, { 0x70, 0x70 }, { 0x71, 0x70 }, /* GSP4, GSP5, GSP6 */
+       { 0x72, 0x70 }, { 0x73, 0x70 }, { 0x74, 0x60 }, /* GSP7, GSP8, GSP9 */
+       { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, /* GSP10,GSP11,GSP12 */
+       { 0x78, 0x3A }, { 0x79, 0x2E }, { 0x7A, 0x28 }, /* GSP13,GSP14,GSP15 */
+       { 0x7B, 0x22 }, { 0x7C, 0x04 }, { 0x7D, 0x07 }, /* GSP16,GST1, GST2 */
+       { 0x7E, 0x10 }, { 0x7F, 0x28 }, { 0x80, 0x36 }, /* GST3, GST4, GST5 */
+       { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, /* GST6, GST7, GST8 */
+       { 0x84, 0x6C }, { 0x85, 0x78 }, { 0x86, 0x8C }, /* GST9, GST10,GST11 */
+       { 0x87, 0x9E }, { 0x88, 0xBB }, { 0x89, 0xD2 }, /* GST12,GST13,GST14 */
+       { 0x8A, 0xE6 }, { 0x13, 0x8F }, { 0x00, 0x7F }, /* GST15, COM8 */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+static int ov9640_sensor_power_set(int power)
+{
+       unsigned char expa;
+       int err;
+
+       /* read current state of GPIO EXPA outputs */
+       if ((err = read_gpio_expa(&expa, 0x20))) {
+               printk(KERN_ERR "Error reading GPIO EXPA 0x20\n");
+               return err;
+       }
+
+       expa = power ? expa | 0x80 : expa & ~0x08;
+
+       /* Set GPIO EXPA P3 (CAMERA_MODULE_EN) to power-up sensor */
+       if ((err = write_gpio_expa(expa, 0x20))) {
+               printk(KERN_ERR "Error writing to GPIO EXPA 0x20\n");
+               return err;
+       }
+
+       if (power) {
+               /* read current state of GPIO EXPA outputs */
+               if ((err = read_gpio_expa(&expa, 0x22))) {
+                       printk(KERN_ERR "Error reading GPIO EXPA\n");
+                       return err;
+               }
+               /* Clear GPIO EXPA P7 (CAM_RST) */
+               if ((err = write_gpio_expa(expa & ~0x80, 0x22))) {
+                       printk(KERN_ERR "Error writing to GPIO EXPA\n");
+                       return err;
+               }
+       }
+
+       return err;
+}
+
+static struct v4l2_ifparm ifparm = {
+       .if_type = V4L2_IF_TYPE_BT656,
+       .u = {
+               .bt656 = {
+                        .frame_start_on_rising_vs = 1,
+                        .nobt_vs_inv = 1,
+                        .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+                        .clock_min = OV9640_XCLK_MIN,
+                        .clock_max = OV9640_XCLK_MAX,
+                },
+       },
+};
+
+static int ov9640_ifparm(struct v4l2_ifparm *p)
+{
+       *p = ifparm;
+
+       return 0;
+}
+
+static struct ov9640_platform_data h4_ov9640_platform_data = {
+       .power_set      = ov9640_sensor_power_set,
+       .default_regs   = ov9640_common,
+       .ifparm         = ov9640_ifparm,
+};
+#endif
+
+static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("rv5c387a", 0x32),
+               /* no IRQ wired to OMAP; nINTB goes to AGPS */
+       },
+       {
+               I2C_BOARD_INFO("menelaus", 0x72),
+               .irq = INT_24XX_SYS_NIRQ,
+       },
+       {
+               I2C_BOARD_INFO("isp1301_omap", 0x2d),
+               .irq            = OMAP_GPIO_IRQ(125),
+       },
+#if defined(CONFIG_VIDEO_OV9640) || defined(CONFIG_VIDEO_OV9640_MODULE)
+       {
+               I2C_BOARD_INFO("ov9640", 0x30),
+               .platform_data = &h4_ov9640_platform_data,
+       },
+#endif
 };
 
 static void __init omap_h4_init(void)
@@ -412,10 +669,57 @@ static void __init omap_h4_init(void)
        }
 #endif
 
+#ifdef CONFIG_MACH_OMAP2_H4_USB1
+       /* S3.3 controls whether these pins are for UART2 or USB1 */
+       omap_cfg_reg(N14_24XX_USB1_SE0);
+       omap_cfg_reg(P15_24XX_USB1_DAT);
+       omap_cfg_reg(W20_24XX_USB1_TXEN);
+       omap_cfg_reg(V19_24XX_USB1_RCV);
+#endif
+
+       /* Menelaus interrupt */
+       omap_cfg_reg(W19_24XX_SYS_NIRQ);
+
+       i2c_register_board_info(1, h4_i2c_board_info,
+                       ARRAY_SIZE(h4_i2c_board_info));
+
        platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
        omap_board_config = h4_config;
        omap_board_config_size = ARRAY_SIZE(h4_config);
        omap_serial_init();
+       h4_mmc_init();
+       omap_register_i2c_bus(1, 100, h4_i2c_board_info,
+                             ARRAY_SIZE(h4_i2c_board_info));
+
+       /* smc91x, debug leds, ps/2, extra uarts */
+       h4_init_debug();
+
+#ifdef CONFIG_MACH_OMAP_H4_TUSB
+       tusb_evm_setup();
+#endif
+
+       /* defaults seem ok for:
+        * omap_cfg_reg(U18_24XX_SPI1_SCK);
+        * omap_cfg_reg(V20_24XX_SPI1_MOSI);
+        * omap_cfg_reg(T18_24XX_SPI1_MISO);
+        * omap_cfg_reg(U19_24XX_SPI1_NCS0);
+        */
+
+       /* TSC2101 */
+       omap_cfg_reg(P20_24XX_GPIO93);
+       gpio_request(93, "tsc_irq");
+       gpio_direction_input(93);
+
+       omap_cfg_reg(W14_24XX_SYS_CLKOUT);      /* mclk */
+       /* defaults seem ok for:
+        * omap_cfg_reg(Y15_EAC_AC_SCLK);       // bclk
+        * omap_cfg_reg(R14_EAC_AC_FS);
+        * omap_cfg_reg(V15_EAC_AC_DOUT);
+        * omap_cfg_reg(W15_EAC_AC_DIN);
+        */
+
+       spi_register_board_info(h4_spi_board_info,
+                               ARRAY_SIZE(h4_spi_board_info));
 }
 
 static void __init omap_h4_map_io(void)
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
new file mode 100644 (file)
index 0000000..a086a95
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * linux/arch/arm/mach-omap2/board-ldp.c
+ *
+ * Copyright (C) 2008 Texas Instruments Inc.
+ * Nishant Kamat <nskamat@ti.com>
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-ldp.h>
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+#include <mach/hsmmc.h>
+#include <mach/usb-musb.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+#define ENABLE_VAUX1_DEDICATED 0x03
+#define ENABLE_VAUX1_DEV_GRP   0x20
+
+#define TWL4030_MSECURE_GPIO   22
+
+static int ts_gpio;
+
+static int __init msecure_init(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+       /* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+       if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+                       system_rev < OMAP3430_REV_ES2_0) {
+               void __iomem *msecure_pad_config_reg =
+                       omap_ctrl_base_get() + 0xA3C;
+               int mux_mask = 0x04;
+               u16 tmp;
+
+               ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+               if (ret < 0) {
+                       printk(KERN_ERR "msecure_init: can't"
+                               "reserve GPIO:%d !\n", TWL4030_MSECURE_GPIO);
+                       goto out;
+               }
+               /*
+                * TWL4030 will be in secure mode if msecure line from OMAP
+                * is low. Make msecure line high in order to change the
+                * TWL4030 RTC time and calender registers.
+                */
+
+               tmp = __raw_readw(msecure_pad_config_reg);
+               tmp &= 0xF8;    /* To enable mux mode 03/04 = GPIO_RTC */
+               tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+               __raw_writew(tmp, msecure_pad_config_reg);
+
+               gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+       }
+out:
+#endif
+       return ret;
+}
+
+/**
+ * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
+ *
+ * @return - void. If request gpio fails then Flag KERN_ERR.
+ */
+static void ads7846_dev_init(void)
+{
+       if (omap_request_gpio(ts_gpio) < 0) {
+               printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+               return;
+       }
+
+       omap_set_gpio_direction(ts_gpio, 1);
+
+       omap_set_gpio_debounce(ts_gpio, 1);
+       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(ts_gpio);
+}
+
+/*
+ * This enable(1)/disable(0) the voltage for TS: uses twl4030 calls
+ */
+static int ads7846_vaux_control(int vaux_cntrl)
+{
+       int ret = 0;
+
+#ifdef CONFIG_TWL4030_CORE
+       /* check for return value of ldo_use: if success it returns 0 */
+       if (vaux_cntrl == VAUX_ENABLE) {
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       ENABLE_VAUX1_DEDICATED, TWL4030_VAUX1_DEDICATED))
+                       return -EIO;
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       ENABLE_VAUX1_DEV_GRP, TWL4030_VAUX1_DEV_GRP))
+                       return -EIO;
+       } else if (vaux_cntrl == VAUX_DISABLE) {
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       0x00, TWL4030_VAUX1_DEDICATED))
+                       return -EIO;
+               if (ret != twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                       0x00, TWL4030_VAUX1_DEV_GRP))
+                       return -EIO;
+       }
+#else
+       ret = -EIO;
+#endif
+       return ret;
+}
+
+static struct ads7846_platform_data tsc2046_config __initdata = {
+       .get_pendown_state      = ads7846_get_pendown_state,
+       .keep_vref_on           = 1,
+       .vaux_control           = ads7846_vaux_control,
+};
+
+
+static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,  /* 0: slave, 1: master */
+};
+
+static struct spi_board_info ldp_spi_board_info[] __initdata = {
+       [0] = {
+               /*
+                * TSC2046 operates at a max freqency of 2MHz, so
+                * operate slightly below at 1.5MHz
+                */
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &tsc2046_mcspi_config,
+               .irq                    = 0,
+               .platform_data          = &tsc2046_config,
+       },
+};
+
+static struct platform_device *ldp_devices[] __initdata = {
+};
+
+static void __init omap_ldp_init_irq(void)
+{
+       omap2_init_common_hw(NULL);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct omap_uart_config ldp_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel ldp_config[] __initdata = {
+       { OMAP_TAG_UART,        &ldp_uart_config },
+};
+
+static int ldp_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630,   9280,   8950,   8620,   8310,
+8020,   7730,   7460,   7200,   6950,   6710,   6470,   6250,   6040,   5830,
+5640,   5450,   5260,   5090,   4920,   4760,   4600,   4450,   4310,   4170,
+4040,   3910,   3790,   3670,   3550
+};
+
+static struct twl4030_bci_platform_data ldp_bci_data = {
+      .battery_tmp_tbl = ldp_batt_table,
+      .tblsize         = ARRAY_SIZE(ldp_batt_table),
+};
+
+static struct twl4030_usb_data ldp_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_gpio_platform_data ldp_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_madc_platform_data ldp_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data ldp_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .bci            = &ldp_bci_data,
+       .madc           = &ldp_madc_data,
+       .usb            = &ldp_usb_data,
+       .gpio           = &ldp_gpio_data,
+};
+
+static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &ldp_twldata,
+       },
+};
+
+static int __init omap_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, ldp_i2c_boardinfo,
+                       ARRAY_SIZE(ldp_i2c_boardinfo));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init omap_ldp_init(void)
+{
+       omap_i2c_init();
+       platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
+       omap_board_config = ldp_config;
+       omap_board_config_size = ARRAY_SIZE(ldp_config);
+       ts_gpio = 54;
+       ldp_spi_board_info[0].irq = OMAP_GPIO_IRQ(ts_gpio);
+       spi_register_board_info(ldp_spi_board_info,
+                               ARRAY_SIZE(ldp_spi_board_info));
+       msecure_init();
+       ads7846_dev_init();
+       omap_serial_init();
+       usb_musb_init();
+       hsmmc_init();
+}
+
+static void __init omap_ldp_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_LDP, "OMAP LDP board")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap_ldp_map_io,
+       .init_irq       = omap_ldp_init_irq,
+       .init_machine   = omap_ldp_init,
+       .timer          = &omap_timer,
+MACHINE_END
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..e28390e
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-audio.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Contact: Juha Yrjola
+ *          Jarkko Nikula <jarkko.nikula@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/spi/tsc2301.h>
+
+#include <asm/io.h>
+#include <mach/eac.h>
+
+#include <mach/dsp_common.h>
+
+#if defined(CONFIG_SPI_TSC2301_AUDIO) && defined(CONFIG_SND_OMAP24XX_EAC)
+#define AUDIO_ENABLED
+
+static struct clk *sys_clkout2;
+static struct clk *sys_clkout2_src;
+static struct clk *func96m_clk;
+static struct device *eac_device;
+static struct device *tsc2301_device;
+
+static int enable_audio;
+static int audio_ok;
+static spinlock_t audio_lock;
+
+/*
+ * Leaving EAC and sys_clkout2 pins multiplexed to those subsystems results
+ * in about 2 mA extra current leak when audios are powered down. The
+ * workaround is to multiplex them to protected mode (with pull-ups enabled)
+ * whenever audio is not being used.
+ */
+static int eac_mux_disabled = 0;
+static int clkout2_mux_disabled = 0;
+static u32 saved_mux[2];
+
+static void n800_enable_eac_mux(void)
+{
+       if (!eac_mux_disabled)
+               return;
+       __raw_writel(saved_mux[1], OMAP2_IO_ADDRESS(0x48000124));
+       eac_mux_disabled = 0;
+}
+
+static void n800_disable_eac_mux(void)
+{
+       if (eac_mux_disabled) {
+               WARN_ON(eac_mux_disabled);
+               return;
+       }
+       saved_mux[1] = __raw_readl(OMAP2_IO_ADDRESS(0x48000124));
+       __raw_writel(0x1f1f1f1f, OMAP2_IO_ADDRESS(0x48000124));
+       eac_mux_disabled = 1;
+}
+
+static void n800_enable_clkout2_mux(void)
+{
+       if (!clkout2_mux_disabled)
+               return;
+       __raw_writel(saved_mux[0], OMAP2_IO_ADDRESS(0x480000e8));
+       clkout2_mux_disabled = 0;
+}
+
+static void n800_disable_clkout2_mux(void)
+{
+       u32 l;
+
+       if (clkout2_mux_disabled) {
+               WARN_ON(clkout2_mux_disabled);
+               return;
+       }
+       saved_mux[0] = __raw_readl(OMAP2_IO_ADDRESS(0x480000e8));
+       l = saved_mux[0] & ~0xff;
+       l |= 0x1f;
+       __raw_writel(l, OMAP2_IO_ADDRESS(0x480000e8));
+       clkout2_mux_disabled = 1;
+}
+
+static int n800_eac_enable_ext_clocks(struct device *dev)
+{
+       BUG_ON(tsc2301_device == NULL);
+       n800_enable_eac_mux();
+       tsc2301_mixer_enable_mclk(tsc2301_device);
+
+       return 0;
+}
+
+static void n800_eac_disable_ext_clocks(struct device *dev)
+{
+       BUG_ON(tsc2301_device == NULL);
+       tsc2301_mixer_disable_mclk(tsc2301_device);
+       n800_disable_eac_mux();
+}
+
+static int n800_audio_set_power(void *pdata, int dac, int adc)
+{
+       BUG_ON(pdata != tsc2301_device);
+       tsc2301_mixer_set_power(tsc2301_device, dac, adc);
+
+       return 0;
+}
+
+static int n800_audio_register_controls(void *pdata, struct snd_card *card)
+{
+       BUG_ON(pdata != tsc2301_device);
+       return tsc2301_mixer_register_controls(tsc2301_device, card);
+}
+
+static struct eac_codec n800_eac_codec = {
+       .mclk_src = EAC_MCLK_EXT_2x12288000,
+       .codec_mode = EAC_CODEC_I2S_MASTER,
+       .codec_conf.i2s.polarity_changed_mode = 0,
+       .codec_conf.i2s.sync_delay_enable = 0,
+       .default_rate = 48000,
+       .set_power = n800_audio_set_power,
+       .register_controls = n800_audio_register_controls,
+       .short_name = "TSC2301",
+};
+
+static int n800_register_codec(void)
+{
+       int r, do_enable = 0;
+       unsigned long flags;
+
+       n800_eac_codec.private_data = tsc2301_device;
+       r = eac_register_codec(eac_device, &n800_eac_codec);
+       if (r < 0)
+               return r;
+       spin_lock_irqsave(&audio_lock, flags);
+       audio_ok = 1;
+       if (enable_audio)
+               do_enable = 1;
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_enable)
+               eac_set_mode(eac_device, 1, 1);
+       return 0;
+}
+
+static void n800_unregister_codec(void)
+{
+       audio_ok = 0;
+       eac_unregister_codec(eac_device);
+       eac_set_mode(eac_device, 0, 0);
+}
+
+static int n800_eac_init(struct device *dev)
+{
+       int r;
+
+       BUG_ON(eac_device != NULL);
+       eac_device = dev;
+       if (tsc2301_device != NULL) {
+               r = n800_register_codec();
+               if (r < 0)
+                       return r;
+       }
+
+       return 0;
+}
+
+static void n800_eac_cleanup(struct device *dev)
+{
+       eac_device = NULL;
+       if (tsc2301_device != NULL)
+               n800_unregister_codec();
+}
+
+static int n800_codec_get_clocks(struct device *dev)
+{
+       sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
+       if (IS_ERR(sys_clkout2_src)) {
+               dev_err(dev, "Could not get sys_clkout2_src clock\n");
+               return -ENODEV;
+       }
+       sys_clkout2 = clk_get(dev, "sys_clkout2");
+       if (IS_ERR(sys_clkout2)) {
+               dev_err(dev, "Could not get sys_clkout2 clock\n");
+               clk_put(sys_clkout2_src);
+               return -ENODEV;
+       }
+       /* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
+        * 96 MHz as its parent in order to get 12 MHz */
+       func96m_clk = clk_get(dev, "func_96m_ck");
+       if (IS_ERR(func96m_clk)) {
+               dev_err(dev, "Could not get func 96M clock\n");
+               clk_put(sys_clkout2);
+               clk_put(sys_clkout2_src);
+               return -ENODEV;
+       }
+
+       clk_set_parent(sys_clkout2_src, func96m_clk);
+       clk_set_rate(sys_clkout2, 12000000);
+
+       return 0;
+}
+
+static void n800_codec_put_clocks(struct device *dev)
+{
+       clk_put(func96m_clk);
+       clk_put(sys_clkout2);
+       clk_put(sys_clkout2_src);
+}
+
+static int n800_codec_enable_clock(struct device *dev)
+{
+       n800_enable_clkout2_mux();
+       return clk_enable(sys_clkout2);
+}
+
+static void n800_codec_disable_clock(struct device *dev)
+{
+       clk_disable(sys_clkout2);
+       n800_disable_clkout2_mux();
+}
+
+static int n800_codec_init(struct device *dev)
+{
+       int r;
+
+       BUG_ON(tsc2301_device != NULL);
+       tsc2301_device = dev;
+       if ((r = n800_codec_get_clocks(dev)) < 0)
+               return r;
+       if (eac_device != NULL) {
+               r = n800_register_codec();
+               if (r < 0) {
+                       n800_codec_put_clocks(dev);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static void n800_codec_cleanup(struct device *dev)
+{
+       tsc2301_device = NULL;
+       if (eac_device != NULL)
+               n800_unregister_codec();
+       n800_codec_put_clocks(dev);
+}
+
+static struct eac_platform_data n800_eac_data = {
+       .init = n800_eac_init,
+       .cleanup = n800_eac_cleanup,
+       .enable_ext_clocks = n800_eac_enable_ext_clocks,
+       .disable_ext_clocks = n800_eac_disable_ext_clocks,
+};
+
+static const struct tsc2301_mixer_gpio n800_mixer_gpios[] = {
+       {
+               .name                   = "Headset Amplifier",
+               .gpio                   = 1,
+               .deactivate_on_pd       = 1,
+       }, {
+               .name                   = "Speaker Amplifier",
+               .gpio                   = 2,
+               .def_enable             = 1,
+               .deactivate_on_pd       = 1,
+       }, {
+               .name                   = "Headset Mic Select",
+               .gpio                   = 3,
+       }
+};
+
+static struct platform_device retu_headset_device = {
+       .name           = "retu-headset",
+       .id             = -1,
+       .dev            = {
+               .release        = NULL,
+       },
+};
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+       spin_lock_init(&audio_lock);
+
+       if (platform_device_register(&retu_headset_device) < 0)
+               return;
+       omap_init_eac(&n800_eac_data);
+
+       tc->pll_pdc = 7;
+       tc->pll_a = 7;
+       tc->pll_n = 9;
+       tc->pll_output = 1;
+       tc->mclk_ratio = TSC2301_MCLK_256xFS;
+       tc->i2s_sample_rate = TSC2301_I2S_SR_48000;
+       tc->i2s_format = TSC2301_I2S_FORMAT0;
+       tc->power_down_blocks = TSC2301_REG_PD_MISC_MOPD;
+       tc->mixer_gpios = n800_mixer_gpios;
+       tc->n_mixer_gpios = ARRAY_SIZE(n800_mixer_gpios);
+       tc->codec_init = n800_codec_init;
+       tc->codec_cleanup = n800_codec_cleanup;
+       tc->enable_clock = n800_codec_enable_clock;
+       tc->disable_clock = n800_codec_disable_clock;
+}
+
+#else
+
+void __init n800_audio_init(struct tsc2301_platform_data *tc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_OMAP_DSP
+
+int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+       unsigned long flags;
+       int do_enable = 0;
+
+       spin_lock_irqsave(&audio_lock, flags);
+
+       pr_debug("DSP power up request (audio codec %sinitialized)\n",
+                audio_ok ? "" : "not ");
+
+       if (enable_audio)
+               goto out;
+       enable_audio = 1;
+       if (audio_ok)
+               do_enable = 1;
+out:
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_enable)
+               eac_set_mode(eac_device, 1, 1);
+#endif
+       return 0;
+}
+
+int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage)
+{
+#ifdef AUDIO_ENABLED
+       unsigned long flags;
+       int do_disable = 0;
+
+       spin_lock_irqsave(&audio_lock, flags);
+
+       pr_debug("DSP power down request (audio codec %sinitialized)\n",
+               audio_ok ? "" : "not ");
+
+       if (!enable_audio)
+               goto out;
+       enable_audio = 0;
+       if (audio_ok)
+               do_disable = 1;
+out:
+       spin_unlock_irqrestore(&audio_lock, flags);
+       if (do_disable)
+               eac_set_mode(eac_device, 0, 0);
+#endif
+       return 0;
+}
+
+#endif /* CONFIG_OMAP_DSP */
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..61afd2b
--- /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 <mach/board.h>
+
+static struct platform_device n800_bt_device = {
+       .name           = "hci_h4p",
+       .id             = -1,
+       .num_resources  = 0,
+};
+
+void __init n800_bt_init(void)
+{
+       const struct omap_bluetooth_config *bt_config;
+
+       bt_config = (void *) omap_get_config(OMAP_TAG_NOKIA_BT,
+                                            struct omap_bluetooth_config);
+       n800_bt_device.dev.platform_data = (void *) bt_config;
+       if (platform_device_register(&n800_bt_device) < 0)
+               BUG();
+}
+
diff --git a/arch/arm/mach-omap2/board-n800-camera.c b/arch/arm/mach-omap2/board-n800-camera.c
new file mode 100644 (file)
index 0000000..6272263
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * arch/arm/mach-omap2/board-n800-camera.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/i2c/menelaus.h>
+
+#include <media/v4l2-int-device.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/gpio.h>
+#include <mach/board.h>
+
+#include <../drivers/cbus/retu.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#include "board-n800.h"
+
+#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+
+#define OMAP24XX_CAMERA_JAM_HACK
+
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+/*
+ * We don't need to check every pixel to assume that the frame is
+ * corrupt and the sensor is jammed. CHECK_X and CHECK_Y are the
+ * number of u32s to check per line / row, plus there are two lines in
+ * the bottom of the frame.
+ */
+#define CHECK_X 8
+#define CHECK_Y 6
+/*
+ * Start checking after this many frames since resetting the sensor.
+ * Sometimes the first frame(s) is(/are) black which could trigger
+ * unwanted reset(s).
+ */
+#define JAM_CHECK_AFTER 3
+/*
+ * If the sensor is quickly brought into bright conditions from dark,
+ * it may temporarily be saturated, leaving out the normal background
+ * noise. This many saturated frames may go through before the sensor
+ * is considered jammed.
+ */
+#define SATURATED_MAX 30
+#endif
+
+#define N800_CAM_SENSOR_RESET_GPIO     53
+
+static int sensor_okay;
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+static int frames_after_reset;
+static int saturated_count;
+#endif
+
+const static struct tcm825x_reg tcm825x_regs_n800[] = {
+       /* initial settings for 2.5 V */
+       {0x00, 0x03}, {0x03, 0x29}, {0xaa, 0x2a}, {0xc0, 0x2b},
+       {0x10, 0x2c}, {0x4c, 0x2d}, {0x9c, 0x3f},
+
+       /* main settings */
+       {0x00, 0x00}, {0x30, 0x01}, {0x0e, 0x02}, /* initial */
+       {0x0f, 0x04}, {0x02, 0x05}, {0x0d, 0x06}, {0xc0, 0x07},
+       {0x38, 0x08}, {0x50, 0x09}, {0x80, 0x0a}, {0x40, 0x0b},
+       {0x40, 0x0c}, {0x00, 0x0d}, {0x04, 0x0e}, {0x04, 0x0f},
+       {0x22, 0x10}, {0x96, 0x11}, {0xf0, 0x12}, {0x08, 0x13},
+       {0x08, 0x14}, {0x30, 0x15}, {0x30, 0x16}, {0x01, 0x17},
+       {0x40, 0x18}, {0x87, 0x19}, {0x2b, 0x1a}, {0x84, 0x1b},
+       {0x52, 0x1c}, {0x44, 0x1d}, {0x68, 0x1e}, {0x00, 0x1f},
+       {0x00, 0x20}, {0x01, 0x21}, {0x27, 0x22}, {0x40, 0x23},
+       {0x27, 0x24}, {0x5f, 0x25}, {0x00, 0x26}, {0x16, 0x27},
+       {0x23, 0x28}, /* initial */ /* initial */ /* initial */
+       /* initial */ /* initial */ {0x00, 0x2e}, {0x00, 0x2f},
+       {0x00, 0x30}, {0x00, 0x31}, {0x00, 0x32}, {0x00, 0x33},
+       {0x00, 0x34}, {0x00, 0x35}, {0x00, 0x36}, {0x00, 0x37},
+       {0x00, 0x38}, {0x8c, 0x39}, {0xc8, 0x3A}, {0x80, 0x3b},
+       {0x00, 0x3c}, {0x17, 0x3d}, {0x85, 0x3e}, /* initial */
+       {0xa0, 0x40}, {0x00, 0x41}, {0x00, 0x42}, {0x00, 0x43},
+       {0x08, 0x44}, {0x12, 0x45}, {0x00, 0x46}, {0x20, 0x47},
+       {0x30, 0x48}, {0x18, 0x49}, {0x20, 0x4a}, {0x4d, 0x4b},
+       {0x0c, 0x4c}, {0xe0, 0x4d}, {0x20, 0x4e}, {0x89, 0x4f},
+       {0x21, 0x50}, {0x80, 0x51}, {0x02, 0x52}, {0x00, 0x53},
+       {0x30, 0x54}, {0x90, 0x55}, {0x40, 0x56}, {0x06, 0x57},
+       {0x0f, 0x58}, {0x23, 0x59}, {0x08, 0x5A}, {0x04, 0x5b},
+       {0x08, 0x5c}, {0x08, 0x5d}, {0x08, 0x5e}, {0x08, 0x5f},
+       {TCM825X_VAL_TERM, TCM825X_REG_TERM}
+};
+
+const static struct tcm825x_reg tcm825x_regs_n810[] = {
+       /* initial settings for 2.5 V */
+       {0x00, 0x03}, {0x03, 0x29}, {0xaa, 0x2a}, {0xc0, 0x2b},
+       {0x10, 0x2c}, {0x4c, 0x2d}, {0x9c, 0x3f},
+
+       /* main settings */
+       {0x00, 0x00}, {0x30, 0x01}, {0x0e, 0x02}, /* initial */
+       {0xcf, 0x04}, {0x02, 0x05}, {0x0d, 0x06}, {0xc0, 0x07},
+       {0x38, 0x08}, {0x50, 0x09}, {0x80, 0x0a}, {0x40, 0x0b},
+       {0x40, 0x0c}, {0x00, 0x0d}, {0x04, 0x0e}, {0x04, 0x0f},
+       {0x22, 0x10}, {0x96, 0x11}, {0xf0, 0x12}, {0x08, 0x13},
+       {0x08, 0x14}, {0x30, 0x15}, {0x30, 0x16}, {0x01, 0x17},
+       {0x40, 0x18}, {0x87, 0x19}, {0x2b, 0x1a}, {0x84, 0x1b},
+       {0x52, 0x1c}, {0x44, 0x1d}, {0x68, 0x1e}, {0x00, 0x1f},
+       {0x00, 0x20}, {0x01, 0x21}, {0x27, 0x22}, {0x40, 0x23},
+       {0x27, 0x24}, {0x5f, 0x25}, {0x00, 0x26}, {0x16, 0x27},
+       {0x23, 0x28}, /* initial */ /* initial */ /* initial */
+       /* initial */ /* initial */ {0x00, 0x2e}, {0x00, 0x2f},
+       {0x00, 0x30}, {0x00, 0x31}, {0x00, 0x32}, {0x00, 0x33},
+       {0x00, 0x34}, {0x00, 0x35}, {0x00, 0x36}, {0x00, 0x37},
+       {0x00, 0x38}, {0x8c, 0x39}, {0xc8, 0x3A}, {0x80, 0x3b},
+       {0x00, 0x3c}, {0x17, 0x3d}, {0x85, 0x3e}, /* initial */
+       {0xa0, 0x40}, {0x00, 0x41}, {0x00, 0x42}, {0x00, 0x43},
+       {0x08, 0x44}, {0x12, 0x45}, {0x00, 0x46}, {0x20, 0x47},
+       {0x30, 0x48}, {0x18, 0x49}, {0x20, 0x4a}, {0x4d, 0x4b},
+       {0x0c, 0x4c}, {0xe0, 0x4d}, {0x20, 0x4e}, {0x89, 0x4f},
+       {0x21, 0x50}, {0x80, 0x51}, {0x02, 0x52}, {0x00, 0x53},
+       {0x30, 0x54}, {0x90, 0x55}, {0x40, 0x56}, {0x06, 0x57},
+       {0x0f, 0x58}, {0x23, 0x59}, {0x08, 0x5A}, {0x04, 0x5b},
+       {0x08, 0x5c}, {0x08, 0x5d}, {0x08, 0x5e}, {0x08, 0x5f},
+       {TCM825X_VAL_TERM, TCM825X_REG_TERM}
+};
+
+static int tcm825x_is_okay(void)
+{
+       return sensor_okay;
+}
+
+/*
+ * VSIM1       --> CAM_IOVDD   --> IOVDD (1.8 V)
+ */
+static int tcm825x_power_on(void)
+{
+       int ret;
+
+       /* Set VMEM to 1.5V and VIO to 2.5V */
+       ret = menelaus_set_vmem(1500);
+       if (ret < 0) {
+               /* Try once more, it seems the sensor power up causes
+                * some problems on the I2C bus. */
+               ret = menelaus_set_vmem(1500);
+               if (ret < 0)
+                       return ret;
+       }
+       msleep(1);
+
+       ret = menelaus_set_vio(2500);
+       if (ret < 0)
+               return ret;
+
+       /* Set VSim1 on */
+       retu_write_reg(RETU_REG_CTRL_SET, 0x0080);
+       msleep(1);
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 1);
+       msleep(1);
+
+       saturated_count = 0;
+       frames_after_reset = 0;
+
+       return 0;
+}
+
+static int tcm825x_power_off(void)
+{
+       int ret;
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+       msleep(1);
+
+       /* Set VSim1 off */
+       retu_write_reg(RETU_REG_CTRL_CLR, 0x0080);
+       msleep(1);
+
+       /* Set VIO_MODE to off */
+       ret = menelaus_set_vio(0);
+       if (ret < 0)
+               return ret;
+       msleep(1);
+
+       /* Set VMEM_MODE to off */
+       ret = menelaus_set_vmem(0);
+       if (ret < 0)
+               return ret;
+       msleep(1);
+
+       return 0;
+}
+
+static int tcm825x_power_set(int power)
+{
+       BUG_ON(!sensor_okay);
+
+       if (power)
+               return tcm825x_power_on();
+       else
+               return tcm825x_power_off();
+}
+
+static const struct tcm825x_reg *tcm825x_default_regs(void)
+{
+       if (machine_is_nokia_n810())
+               return tcm825x_regs_n810;
+
+       return tcm825x_regs_n800;
+}
+
+#ifdef OMAP24XX_CAMERA_JAM_HACK
+/*
+ * Check for jammed sensor, in which case all horizontal lines are
+ * equal. Handle also case where sensor could be saturated awhile in
+ * case of rapid increase of brightness.
+ */
+static int tcm825x_needs_reset(struct v4l2_int_device *s, void *buf,
+                              struct v4l2_pix_format *pix)
+{
+       int i, j;
+       uint32_t xor, xor2;
+       uint32_t offset;
+       uint32_t dx_offset;
+       uint32_t saturated_pattern;
+       int is_saturated = 1;
+
+       switch (pix->pixelformat) {
+       default:
+       case V4L2_PIX_FMT_RGB565:
+               saturated_pattern = 0xffffffff; /* guess */
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               saturated_pattern = 0xe080e080;
+               break;
+       }
+
+       /* This won't work for height under 2 at all. */
+       if (pix->height < 2)
+               return 0;
+       /* Check that there is enough image data. */
+       if (pix->width * TCM825X_BYTES_PER_PIXEL < sizeof(uint32_t))
+               return 0;
+       /*
+        * Don't check for jamming immediately. Sometimes frames
+        * immediately after reset are black.
+        */
+       if (frames_after_reset < JAM_CHECK_AFTER) {
+               frames_after_reset++;
+               return 0;
+       }
+
+       dx_offset = ((pix->width - sizeof(uint32_t) / TCM825X_BYTES_PER_PIXEL)
+                    * TCM825X_BYTES_PER_PIXEL) / (CHECK_X - 1);
+       dx_offset = dx_offset - dx_offset % TCM825X_BYTES_PER_PIXEL;
+       /*
+        * Check two lines in the bottom first. They're unlikely to be
+        * saturated and quick to check.
+        */
+       offset = (pix->height - 2) * pix->bytesperline;
+       xor = xor2 = 0;
+       for (j = 0; j < CHECK_X; j++) {
+               uint32_t *val = buf + offset;
+               uint32_t *val2 = buf + offset + pix->bytesperline;
+               xor ^= *val;
+               if (*val != saturated_pattern)
+                       is_saturated = 0;
+               xor2 ^= *val2;
+               if (xor2 != xor) {
+                       saturated_count = 0;
+                       return 0;
+               }
+               offset += dx_offset;
+       }
+       /* Check the rest of the picture. */
+       offset = 0;
+       for (i = 0; i < CHECK_Y; i++) {
+               uint32_t offset2 = offset;
+               xor2 = 0;
+               for (j = 0; j < CHECK_X; j++) {
+                       uint32_t *val = buf + offset2;
+                       xor2 ^= *val;
+                       offset2 += dx_offset;
+               }
+               if (xor2 != xor) {
+                       saturated_count = 0;
+                       return 0;
+               }
+               offset += pix->bytesperline * ((pix->height - 2) / CHECK_Y);
+       }
+
+       if (is_saturated && saturated_count++ < SATURATED_MAX)
+               return 0;
+
+       return -EIO;
+}
+#else
+static int tcm825x_needs_reset(struct v4l2_int_device *s, void *buf,
+                              struct v4l2_pix_format *pix)
+{
+       return 0;
+}
+#endif
+
+static const struct v4l2_ifparm ifparm = {
+       .if_type = V4L2_IF_TYPE_BT656,
+       .u = {
+               .bt656 = {
+                        .frame_start_on_rising_vs = 1,
+                        .latch_clk_inv = 1,
+                        .mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
+                        .clock_min = TCM825X_XCLK_MIN,
+                        .clock_max = TCM825X_XCLK_MAX,
+                },
+       },
+};
+
+static int tcm825x_ifparm(struct v4l2_ifparm *p)
+{
+       *p = ifparm;
+
+       return 0;
+}
+
+static int tcm825x_is_upside_down(void)
+{
+       return machine_is_nokia_n810();
+}
+
+const struct tcm825x_platform_data n800_tcm825x_platform_data = {
+       .is_okay        = tcm825x_is_okay,
+       .power_set      = tcm825x_power_set,
+       .default_regs   = tcm825x_default_regs,
+       .needs_reset    = tcm825x_needs_reset,
+       .ifparm         = tcm825x_ifparm,
+       .is_upside_down = tcm825x_is_upside_down,
+};
+
+void __init n800_cam_init(void)
+{
+       int r;
+
+       r = omap_request_gpio(N800_CAM_SENSOR_RESET_GPIO);
+       if (r < 0) {
+               printk(KERN_WARNING "%s: failed to request gpio\n",
+                       __func__);
+               return;
+       }
+
+       omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0);
+       omap_set_gpio_direction(N800_CAM_SENSOR_RESET_GPIO, 0);
+
+       sensor_okay = 1;
+}
+
+#else
+void __init n800_cam_init(void)
+{
+}
+
+#endif
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..5f3f0d6
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-dsp.c
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <mach/clock.h>
+#include <mach/board.h>
+#include <mach/dsp_common.h>
+
+#if    defined(CONFIG_OMAP_DSP)
+
+/*
+ * dsp peripheral device: AUDIO
+ */
+static struct dsp_kfunc_device n800_audio_device = {
+       .name    = "audio",
+       .type    = DSP_KFUNC_DEV_TYPE_AUDIO,
+       .enable  = n800_audio_enable,
+       .disable = n800_audio_disable,
+};
+
+/*
+ * dsp peripheral device: TIMER
+ */
+static int dsp_timer_probe(struct dsp_kfunc_device *kdev, int stage)
+{
+       char clockname[20];
+
+       strcpy(clockname, kdev->name);
+       strcat(clockname, "_fck");
+
+       kdev->fck = clk_get(NULL, clockname);
+       if (IS_ERR(kdev->fck)) {
+               printk(KERN_ERR "couldn't acquire %s\n", clockname);
+               return PTR_ERR(kdev->fck);
+       }
+       pr_debug("%s probed successfully\n", clockname);
+
+       strcpy(clockname, kdev->name);
+       strcat(clockname, "_ick");
+       kdev->ick = clk_get(NULL, clockname);
+       if (IS_ERR(kdev->ick)) {
+               printk(KERN_ERR "couldn't acquire %s\n", clockname);
+               goto fail;
+       }
+       pr_debug("%s probed successfully\n", clockname);
+
+       return 0;
+ fail:
+       clk_put(kdev->fck);
+
+       return PTR_ERR(kdev->ick);
+}
+
+static int dsp_timer_remove(struct dsp_kfunc_device *kdev, int stage)
+{
+       clk_put(kdev->ick);
+       clk_put(kdev->fck);
+       pr_debug("%s removed successfully\n", kdev->name);
+       return 0;
+}
+
+static int dsp_timer_enable(struct dsp_kfunc_device *kdev, int stage)
+{
+       pr_debug("%s enabled(%d)\n", kdev->name, stage);
+
+       spin_lock(&kdev->lock);
+
+       if (kdev->enabled)
+               goto out;
+       kdev->enabled = 1;
+
+       clk_enable(kdev->fck);
+       clk_enable(kdev->ick);
+ out:
+       spin_unlock(&kdev->lock);
+
+       return 0;
+}
+
+static int dsp_timer_disable(struct dsp_kfunc_device *kdev, int stage)
+{
+       pr_debug("%s disabled(%d)\n", kdev->name, stage);
+
+       spin_lock(&kdev->lock);
+
+       if (kdev->enabled == 0)
+               goto out;
+       kdev->enabled = 0;
+
+       clk_disable(kdev->ick);
+       clk_disable(kdev->fck);
+ out:
+       spin_unlock(&kdev->lock);
+
+       return 0;
+}
+
+static struct dsp_kfunc_device n800_timer_device = {
+       .name    = "gpt5",
+       .type    = DSP_KFUNC_DEV_TYPE_COMMON,
+       .probe   = dsp_timer_probe,
+       .remove  = dsp_timer_remove,
+       .enable  = dsp_timer_enable,
+       .disable = dsp_timer_disable,
+};
+
+static struct dsp_kfunc_device *n800_kfunc_dev[] = {
+       &n800_audio_device,
+       &n800_timer_device,
+};
+
+void __init n800_dsp_init(void)
+{
+       int i, ret;
+       struct dsp_kfunc_device **p = n800_kfunc_dev;
+
+       for (i = 0; i < ARRAY_SIZE(n800_kfunc_dev); i++) {
+               ret = dsp_kfunc_device_register(p[i]);
+               if (ret) {
+                       printk(KERN_ERR
+                              "KFUNC device registration failed: %s\n",
+                              p[i]->name);
+               }
+       }
+}
+
+#else
+void __init n800_dsp_init(void) { }
+#endif /* CONFIG_OMAP_DSP */
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..52aaf76
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-flash.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach/flash.h>
+#include <linux/mtd/onenand_regs.h>
+
+#include <asm/io.h>
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+
+struct mtd_partition n800_partitions[ONENAND_MAX_PARTITIONS];
+
+int n800_onenand_setup(void __iomem *, int freq);
+
+static struct omap_onenand_platform_data n800_onenand_data = {
+       .cs = 0,
+       .parts = n800_partitions,
+       .nr_parts = 0, /* filled later */
+       .onenand_setup = n800_onenand_setup,
+};
+
+static struct platform_device n800_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &n800_onenand_data,
+       },
+};
+
+static int omap2_onenand_set_async_mode(int cs, void __iomem *onenand_base)
+{
+       struct gpmc_timings t;
+
+       const int t_cer = 15;
+       const int t_avdp = 12;
+       const int t_aavdh = 7;
+       const int t_ce = 76;
+       const int t_aa = 76;
+       const int t_oe = 20;
+       const int t_cez = 20; /* max of t_cez, t_oez */
+       const int t_ds = 30;
+       const int t_wpl = 40;
+       const int t_wph = 30;
+
+       memset(&t, 0, sizeof(t));
+       t.sync_clk = 0;
+       t.cs_on = 0;
+       t.adv_on = 0;
+
+       /* Read */
+       t.adv_rd_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+       t.oe_on  = t.adv_rd_off + gpmc_round_ns_to_ticks(t_aavdh);
+       t.access = t.adv_on + gpmc_round_ns_to_ticks(t_aa);
+       t.access = max_t(int, t.access, t.cs_on + gpmc_round_ns_to_ticks(t_ce));
+       t.access = max_t(int, t.access, t.oe_on + gpmc_round_ns_to_ticks(t_oe));
+       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+       t.cs_rd_off = t.oe_off;
+       t.rd_cycle  = t.cs_rd_off + gpmc_round_ns_to_ticks(t_cez);
+
+       /* Write */
+       t.adv_wr_off = t.adv_rd_off;
+       t.we_on  = t.oe_on;
+       if (cpu_is_omap34xx()) {
+               t.wr_data_mux_bus = t.we_on;
+               t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+       }
+       t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+       t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+       t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+
+       /* Configure GPMC for asynchronous read */
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_DEVICESIZE_16 |
+                         GPMC_CONFIG1_MUXADDDATA);
+
+       return gpmc_cs_set_timings(cs, &t);
+}
+
+static unsigned short omap2_onenand_readw(void __iomem *addr)
+{
+       return readw(addr);
+}
+
+static void omap2_onenand_writew(unsigned short value, void __iomem *addr)
+{
+       writew(value, addr);
+}
+
+static void set_onenand_cfg(void __iomem *onenand_base, int latency,
+                           int sync_write, int hf)
+{
+       u32 reg;
+
+       reg = omap2_onenand_readw(onenand_base + ONENAND_REG_SYS_CFG1);
+       reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9));
+       reg |=  (latency << ONENAND_SYS_CFG1_BRL_SHIFT) |
+               ONENAND_SYS_CFG1_SYNC_READ |
+               ONENAND_SYS_CFG1_BL_16;
+       if (sync_write)
+               reg |= ONENAND_SYS_CFG1_SYNC_WRITE;
+       else
+               reg &= ~ONENAND_SYS_CFG1_SYNC_WRITE;
+       if (hf)
+               reg |= ONENAND_SYS_CFG1_HF;
+       else
+               reg &= ~ONENAND_SYS_CFG1_HF;
+       omap2_onenand_writew(reg, onenand_base + ONENAND_REG_SYS_CFG1);
+}
+
+static int omap2_onenand_set_sync_mode(int cs, void __iomem *onenand_base,
+                                      int freq)
+{
+       struct gpmc_timings t;
+       const int t_cer  = 15;
+       const int t_avdp = 12;
+       const int t_cez  = 20; /* max of t_cez, t_oez */
+       const int t_ds   = 30;
+       const int t_wpl  = 40;
+       const int t_wph  = 30;
+       int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
+       int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+       int err, ticks_cez, sync_write = 0, first_time = 0, hf = 0;
+       u32 reg;
+
+       if (!freq) {
+               /* Very first call freq is not known */
+               err = omap2_onenand_set_async_mode(cs, onenand_base);
+               if (err)
+                       return err;
+               reg = omap2_onenand_readw(onenand_base +
+                                         ONENAND_REG_VERSION_ID);
+               switch ((reg >> 4) & 0xf) {
+               case 0:
+                       freq = 40;
+                       break;
+               case 1:
+                       freq = 54;
+                       break;
+               case 2:
+                       freq = 66;
+                       break;
+               case 3:
+                       freq = 83;
+                       break;
+               case 4:
+                       freq = 104;
+                       break;
+               default:
+                       freq = 54;
+                       break;
+               }
+               first_time = 1;
+       }
+
+       switch (freq) {
+       case 83:
+               min_gpmc_clk_period = 12; /* 83 MHz */
+               t_ces   = 5;
+               t_avds  = 4;
+               t_avdh  = 2;
+               t_ach   = 6;
+               t_aavdh = 6;
+               t_rdyo  = 9;
+               if (cpu_is_omap34xx())
+                       sync_write = 1;
+               break;
+       case 66:
+               min_gpmc_clk_period = 15; /* 66 MHz */
+               t_ces   = 6;
+               t_avds  = 5;
+               t_avdh  = 2;
+               t_ach   = 6;
+               t_aavdh = 6;
+               t_rdyo  = 11;
+               if (cpu_is_omap34xx())
+                       sync_write = 1;
+               break;
+       default:
+               min_gpmc_clk_period = 18; /* 54 MHz */
+               t_ces   = 7;
+               t_avds  = 7;
+               t_avdh  = 7;
+               t_ach   = 9;
+               t_aavdh = 7;
+               t_rdyo  = 15;
+               break;
+       }
+
+       tick_ns = gpmc_ticks_to_ns(1);
+       div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
+       gpmc_clk_ns = gpmc_ticks_to_ns(div);
+       if (gpmc_clk_ns < 15) /* >66Mhz */
+               hf = 1;
+       if (hf)
+               latency = 6;
+       else if (gpmc_clk_ns >= 25) /* 40 MHz*/
+               latency = 3;
+       else
+               latency = 4;
+
+       if (first_time)
+               set_onenand_cfg(onenand_base, latency, sync_write, hf);
+
+       if (div == 1) {
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+               reg |= (1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+               reg |= (1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+               reg |= (1 << 7);
+               reg |= (1 << 23);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+       } else {
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG2);
+               reg &= ~(1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG2, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG3);
+               reg &= ~(1 << 7);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG3, reg);
+               reg = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG4);
+               reg &= ~(1 << 7);
+               reg &= ~(1 << 23);
+               gpmc_cs_write_reg(cs, GPMC_CS_CONFIG4, reg);
+       }
+
+       /* Set synchronous read timings */
+       memset(&t, 0, sizeof(t));
+       t.sync_clk = min_gpmc_clk_period;
+       t.cs_on = 0;
+       t.adv_on = 0;
+       fclk_offset_ns = gpmc_round_ns_to_ticks(max_t(int, t_ces, t_avds));
+       fclk_offset = gpmc_ns_to_ticks(fclk_offset_ns);
+       t.page_burst_access = gpmc_clk_ns;
+
+       /* Read */
+       t.adv_rd_off = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_avdh));
+       t.oe_on = gpmc_ticks_to_ns(fclk_offset + gpmc_ns_to_ticks(t_ach));
+       t.access = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div);
+       t.oe_off = t.access + gpmc_round_ns_to_ticks(1);
+       t.cs_rd_off = t.oe_off;
+       ticks_cez = ((gpmc_ns_to_ticks(t_cez) + div - 1) / div) * div;
+       t.rd_cycle = gpmc_ticks_to_ns(fclk_offset + (latency + 1) * div +
+                    ticks_cez);
+
+       /* Write */
+       if (sync_write) {
+               t.adv_wr_off = t.adv_rd_off;
+               t.we_on  = 0;
+               t.we_off = t.cs_rd_off;
+               t.cs_wr_off = t.cs_rd_off;
+               t.wr_cycle  = t.rd_cycle;
+               if (cpu_is_omap34xx()) {
+                       t.wr_data_mux_bus = gpmc_ticks_to_ns(fclk_offset +
+                                       gpmc_ns_to_ticks(min_gpmc_clk_period +
+                                       t_rdyo));
+                       t.wr_access = t.access;
+               }
+       } else {
+               t.adv_wr_off = gpmc_round_ns_to_ticks(max_t(int, t_avdp, t_cer));
+               t.we_on  = t.adv_wr_off + gpmc_round_ns_to_ticks(t_aavdh);
+               t.we_off = t.we_on + gpmc_round_ns_to_ticks(t_wpl);
+               t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(t_wph);
+               t.wr_cycle  = t.cs_wr_off + gpmc_round_ns_to_ticks(t_cez);
+               if (cpu_is_omap34xx()) {
+                       t.wr_data_mux_bus = t.we_on;
+                       t.wr_access = t.we_on + gpmc_round_ns_to_ticks(t_ds);
+               }
+       }
+
+       /* Configure GPMC for synchronous read */
+       gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1,
+                         GPMC_CONFIG1_WRAPBURST_SUPP |
+                         GPMC_CONFIG1_READMULTIPLE_SUPP |
+                         GPMC_CONFIG1_READTYPE_SYNC |
+                         (sync_write ? GPMC_CONFIG1_WRITEMULTIPLE_SUPP : 0) |
+                         (sync_write ? GPMC_CONFIG1_WRITETYPE_SYNC : 0) |
+                         GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) |
+                         GPMC_CONFIG1_PAGE_LEN(2) |
+                         (cpu_is_omap34xx() ? 0 :
+                               (GPMC_CONFIG1_WAIT_READ_MON |
+                                GPMC_CONFIG1_WAIT_PIN_SEL(0))) |
+                         GPMC_CONFIG1_DEVICESIZE_16 |
+                         GPMC_CONFIG1_DEVICETYPE_NOR |
+                         GPMC_CONFIG1_MUXADDDATA);
+
+       err = gpmc_cs_set_timings(cs, &t);
+       if (err)
+               return err;
+
+       set_onenand_cfg(onenand_base, latency, sync_write, hf);
+
+       return 0;
+}
+
+int n800_onenand_setup(void __iomem *onenand_base, int freq)
+{
+       struct omap_onenand_platform_data *datap = &n800_onenand_data;
+       struct device *dev = &n800_onenand_device.dev;
+
+       /* Set sync timings in GPMC */
+       if (omap2_onenand_set_sync_mode(datap->cs, onenand_base, freq) < 0) {
+               dev_err(dev, "Unable to set synchronous mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void __init n800_flash_init(void)
+{
+       const struct omap_partition_config *part;
+       int i = 0;
+
+       n800_onenand_data.gpio_irq = cpu_is_omap34xx() ? 65 : 26;
+
+       while ((part = omap_get_nr_config(OMAP_TAG_PARTITION,
+                               struct omap_partition_config, i)) != NULL) {
+               struct mtd_partition *mpart;
+
+               mpart = n800_partitions + i;
+               mpart->name = (char *) part->name;
+               mpart->size = part->size;
+               mpart->offset = part->offset;
+               mpart->mask_flags = part->mask_flags;
+               i++;
+               if (i == ARRAY_SIZE(n800_partitions)) {
+                       printk(KERN_ERR "Too many partitions supplied\n");
+                       return;
+               }
+       }
+       n800_onenand_data.nr_parts = i;
+       if (platform_device_register(&n800_onenand_device) < 0) {
+               printk(KERN_ERR "Unable to register OneNAND device\n");
+               return;
+       }
+}
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..9242356
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-mmc.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/menelaus.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/mmc.h>
+#include <mach/gpio.h>
+
+#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+static const int slot_switch_gpio = 96;
+
+static const int n810_slot2_pw_vddf = 23;
+static const int n810_slot2_pw_vdd = 9;
+
+static int slot1_cover_open;
+static int slot2_cover_open;
+static struct device *mmc_device;
+
+/*
+ * VMMC   --> slot 1 (N800 & N810)
+ * VDCDC3_APE, VMCS2_APE --> slot 2 on N800
+ * GPIO96 --> Menelaus GPIO2
+ * GPIO23 --> controls slot2 VSD    (N810 only)
+ * GPIO9  --> controls slot2 VIO_SD (N810 only)
+ */
+
+static int n800_mmc_switch_slot(struct device *dev, int slot)
+{
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Choose slot %d\n", slot + 1);
+#endif
+       if (slot == 0)
+               omap_set_gpio_dataout(slot_switch_gpio, 0);
+       else
+               omap_set_gpio_dataout(slot_switch_gpio, 1);
+       return 0;
+}
+
+static int n800_mmc_set_power_menelaus(struct device *dev, int slot,
+                                       int power_on, int vdd)
+{
+       int mV;
+
+#ifdef CONFIG_MMC_DEBUG
+       dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,
+               power_on ? "on" : "off", vdd);
+#endif
+       if (slot == 0) {
+               if (!power_on)
+                       return menelaus_set_vmmc(0);
+               switch (1 << vdd) {
+               case MMC_VDD_33_34:
+               case MMC_VDD_32_33:
+               case MMC_VDD_31_32:
+                       mV = 3100;
+                       break;
+               case MMC_VDD_30_31:
+                       mV = 3000;
+                       break;
+               case MMC_VDD_28_29:
+                       mV = 2800;
+                       break;
+               case MMC_VDD_165_195:
+                       mV = 1850;
+                       break;
+               default:
+                       BUG();
+               }
+               return menelaus_set_vmmc(mV);
+       } else {
+               if (!power_on)
+                       return menelaus_set_vdcdc(3, 0);
+               switch (1 << vdd) {
+               case MMC_VDD_33_34:
+               case MMC_VDD_32_33:
+                       mV = 3300;
+                       break;
+               case MMC_VDD_30_31:
+               case MMC_VDD_29_30:
+                       mV = 3000;
+                       break;
+               case MMC_VDD_28_29:
+               case MMC_VDD_27_28:
+                       mV = 2800;
+                       break;
+               case MMC_VDD_24_25:
+               case MMC_VDD_23_24:
+                       mV = 2400;
+                       break;
+               case MMC_VDD_22_23:
+               case MMC_VDD_21_22:
+                       mV = 2200;
+                       break;
+               case MMC_VDD_20_21:
+                       mV = 2000;
+                       break;
+               case MMC_VDD_165_195:
+                       mV = 1800;
+                       break;
+               default:
+                       BUG();
+               }
+               return menelaus_set_vdcdc(3, mV);
+       }
+       return 0;
+}
+
+static void nokia_mmc_set_power_internal(struct device *dev,
+                                        int power_on)
+{
+       dev_dbg(dev, "Set internal slot power %s\n",
+               power_on ? "on" : "off");
+
+       if (power_on) {
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 1);
+               udelay(30);
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 1);
+               udelay(100);
+       } else {
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+               msleep(50);
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+               msleep(50);
+       }
+}
+
+static int n800_mmc_set_power(struct device *dev, int slot, int power_on,
+                             int vdd)
+{
+       if (machine_is_nokia_n800() || slot == 0)
+               return n800_mmc_set_power_menelaus(dev, slot, power_on, vdd);
+
+       nokia_mmc_set_power_internal(dev, power_on);
+
+       return 0;
+}
+
+static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode)
+{
+       int r;
+
+       dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,
+               bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");
+       BUG_ON(slot != 0 && slot != 1);
+       slot++;
+       switch (bus_mode) {
+       case MMC_BUSMODE_OPENDRAIN:
+               r = menelaus_set_mmc_opendrain(slot, 1);
+               break;
+       case MMC_BUSMODE_PUSHPULL:
+               r = menelaus_set_mmc_opendrain(slot, 0);
+               break;
+       default:
+               BUG();
+       }
+       if (r != 0 && printk_ratelimit())
+               dev_err(dev, "MMC: unable to set bus mode for slot %d\n",
+                       slot);
+       return r;
+}
+
+static int n800_mmc_get_cover_state(struct device *dev, int slot)
+{
+       slot++;
+       BUG_ON(slot != 1 && slot != 2);
+       if (slot == 1)
+               return slot1_cover_open;
+       else
+               return slot2_cover_open;
+}
+
+static void n800_mmc_callback(void *data, u8 card_mask)
+{
+       int bit, *openp, index;
+
+       if (machine_is_nokia_n800()) {
+               bit = 1 << 1;
+               openp = &slot2_cover_open;
+               index = 1;
+       } else {
+               bit = 1;
+               openp = &slot1_cover_open;
+               index = 0;
+       }
+
+       if (card_mask & bit)
+               *openp = 1;
+       else
+               *openp = 0;
+
+       omap_mmc_notify_cover_event(mmc_device, index, *openp);
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int closed_state)
+{
+       if (mmc_device == NULL)
+               return;
+
+       slot1_cover_open = !closed_state;
+       omap_mmc_notify_cover_event(mmc_device, 0, closed_state);
+}
+
+static int n800_mmc_late_init(struct device *dev)
+{
+       int r, bit, *openp;
+       int vs2sel;
+
+       mmc_device = dev;
+
+       r = menelaus_set_slot_sel(1);
+       if (r < 0)
+               return r;
+
+       if (machine_is_nokia_n800())
+               vs2sel = 0;
+       else
+               vs2sel = 2;
+
+       r = menelaus_set_mmc_slot(2, 0, vs2sel, 1);
+       if (r < 0)
+               return r;
+
+       n800_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */
+       n800_mmc_set_power(dev, 1, MMC_POWER_ON, 16);
+
+       r = menelaus_set_mmc_slot(1, 1, 0, 1);
+       if (r < 0)
+               return r;
+       r = menelaus_set_mmc_slot(2, 1, vs2sel, 1);
+       if (r < 0)
+               return r;
+
+       r = menelaus_get_slot_pin_states();
+       if (r < 0)
+               return r;
+
+       if (machine_is_nokia_n800()) {
+               bit = 1 << 1;
+               openp = &slot2_cover_open;
+       } else {
+               bit = 1;
+               openp = &slot1_cover_open;
+               slot2_cover_open = 0;
+       }
+
+       /* All slot pin bits seem to be inversed until first swith change */
+       if (r == 0xf || r == (0xf & ~bit))
+               r = ~r;
+
+       if (r & bit)
+               *openp = 1;
+       else
+               *openp = 0;
+
+       r = menelaus_register_mmc_callback(n800_mmc_callback, NULL);
+
+       return r;
+}
+
+static void n800_mmc_shutdown(struct device *dev)
+{
+       int vs2sel;
+
+       if (machine_is_nokia_n800())
+               vs2sel = 0;
+       else
+               vs2sel = 2;
+
+       menelaus_set_mmc_slot(1, 0, 0, 0);
+       menelaus_set_mmc_slot(2, 0, vs2sel, 0);
+}
+
+static void n800_mmc_cleanup(struct device *dev)
+{
+       menelaus_unregister_mmc_callback();
+
+       omap_free_gpio(slot_switch_gpio);
+
+       if (machine_is_nokia_n810()) {
+               omap_free_gpio(n810_slot2_pw_vddf);
+               omap_free_gpio(n810_slot2_pw_vdd);
+       }
+}
+
+/*
+ * MMC controller1 has two slots that are multiplexed via I2C.
+ * MMC controller2 is not in use.
+ */
+static struct omap_mmc_platform_data mmc1_data = {
+       .nr_slots               = 2,
+       .switch_slot            = n800_mmc_switch_slot,
+       .init                   = n800_mmc_late_init,
+       .cleanup                = n800_mmc_cleanup,
+       .shutdown               = n800_mmc_shutdown,
+       .max_freq               = 24000000,
+       .dma_mask               = 0xffffffff,
+       .slots[0] = {
+               .wire4          = 1,
+               .set_power      = n800_mmc_set_power,
+               .set_bus_mode   = n800_mmc_set_bus_mode,
+               .get_cover_state= n800_mmc_get_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_30_31 |
+                                 MMC_VDD_32_33   | MMC_VDD_33_34,
+               .name           = "internal",
+       },
+       .slots[1] = {
+               .set_power      = n800_mmc_set_power,
+               .set_bus_mode   = n800_mmc_set_bus_mode,
+               .get_cover_state= n800_mmc_get_cover_state,
+               .ocr_mask       = MMC_VDD_165_195 | MMC_VDD_20_21 |
+                                 MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 |
+                                 MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 |
+                                 MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 |
+                                 MMC_VDD_33_34,
+               .name           = "external",
+       },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
+
+void __init n800_mmc_init(void)
+
+{
+       if (machine_is_nokia_n810()) {
+               mmc1_data.slots[0].name = "external";
+
+               /*
+                * Some Samsung Movinand chips do not like open-ended
+                * multi-block reads and fall to braind-dead state
+                * while doing so. Reducing the number of blocks in
+                * the transfer or delays in clock disable do not help
+                */
+               mmc1_data.slots[1].name = "internal";
+               mmc1_data.slots[1].ban_openended = 1;
+       }
+
+       if (omap_request_gpio(slot_switch_gpio) < 0)
+               BUG();
+       omap_set_gpio_dataout(slot_switch_gpio, 0);
+       omap_set_gpio_direction(slot_switch_gpio, 0);
+
+       if (machine_is_nokia_n810()) {
+               if (omap_request_gpio(n810_slot2_pw_vddf) < 0)
+                       BUG();
+               omap_set_gpio_dataout(n810_slot2_pw_vddf, 0);
+               omap_set_gpio_direction(n810_slot2_pw_vddf, 0);
+
+               if (omap_request_gpio(n810_slot2_pw_vdd) < 0)
+                       BUG();
+               omap_set_gpio_dataout(n810_slot2_pw_vdd, 0);
+               omap_set_gpio_direction(n810_slot2_pw_vdd, 0);
+       }
+
+       mmc_data[0] = &mmc1_data;
+       omap2_init_mmc(mmc_data, OMAP24XX_NR_MMC);
+}
+#else
+
+void __init n800_mmc_init(void)
+{
+}
+
+void n800_mmc_slot1_cover_handler(void *arg, int state)
+{
+}
+
+#endif
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..f8df19e
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800-usb.c
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/usb/musb.h>
+#include <mach/gpmc.h>
+#include <mach/gpio.h>
+#include <mach/pm.h>
+
+#define TUSB_ASYNC_CS          1
+#define TUSB_SYNC_CS           4
+#define GPIO_TUSB_INT          58
+#define GPIO_TUSB_ENABLE       0
+
+static int tusb_set_power(int state);
+static int tusb_set_clock(struct clk *osc_ck, int state);
+
+#if    defined(CONFIG_USB_MUSB_OTG)
+#      define BOARD_MODE       MUSB_OTG
+#elif  defined(CONFIG_USB_MUSB_PERIPHERAL)
+#      define BOARD_MODE       MUSB_PERIPHERAL
+#else  /* defined(CONFIG_USB_MUSB_HOST) */
+#      define BOARD_MODE       MUSB_HOST
+#endif
+
+static struct musb_hdrc_eps_bits musb_eps[] = {
+       {       "ep1_tx", 5,    },
+       {       "ep1_rx", 5,    },
+       {       "ep2_tx", 5,    },
+       {       "ep2_rx", 5,    },
+       {       "ep3_tx", 3,    },
+       {       "ep3_rx", 3,    },
+       {       "ep4_tx", 3,    },
+       {       "ep4_rx", 3,    },
+       {       "ep5_tx", 2,    },
+       {       "ep5_rx", 2,    },
+       {       "ep6_tx", 2,    },
+       {       "ep6_rx", 2,    },
+       {       "ep7_tx", 2,    },
+       {       "ep7_rx", 2,    },
+       {       "ep8_tx", 2,    },
+       {       "ep8_rx", 2,    },
+       {       "ep9_tx", 2,    },
+       {       "ep9_rx", 2,    },
+       {       "ep10_tx", 2,   },
+       {       "ep10_rx", 2,   },
+       {       "ep11_tx", 2,   },
+       {       "ep11_rx", 2,   },
+       {       "ep12_tx", 2,   },
+       {       "ep12_rx", 2,   },
+       {       "ep13_tx", 2,   },
+       {       "ep13_rx", 2,   },
+       {       "ep14_tx", 2,   },
+       {       "ep14_rx", 2,   },
+       {       "ep15_tx", 2,   },
+       {       "ep15_rx", 2,   },
+};
+
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 1,
+       .dyn_fifo       = 1,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 32,
+       .dma_channels   = 7,
+       .ram_bits       = 12,
+       .eps_bits       = musb_eps,
+};
+
+static struct musb_hdrc_platform_data tusb_data = {
+       .mode           = BOARD_MODE,
+       .set_power      = tusb_set_power,
+       .set_clock      = tusb_set_clock,
+       .min_power      = 25,   /* x2 = 50 mA drawn from VBUS as peripheral */
+       .power          = 100,  /* Max 100 mA VBUS for host mode */
+       .clock          = "osc_ck",
+       .config         = &musb_config,
+};
+
+/*
+ * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
+ * 1.5 V voltage regulators of PM companion chip. Companion chip will then
+ * provide then PGOOD signal to TUSB6010 which will release it from reset.
+ */
+static int tusb_set_power(int state)
+{
+       int i, retval = 0;
+
+       if (state) {
+               omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 1);
+               msleep(1);
+
+               /* Wait until TUSB6010 pulls INT pin down */
+               i = 100;
+               while (i && omap_get_gpio_datain(GPIO_TUSB_INT)) {
+                       msleep(1);
+                       i--;
+               }
+
+               if (!i) {
+                       printk(KERN_ERR "tusb: powerup failed\n");
+                       retval = -ENODEV;
+               }
+       } else {
+               omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 0);
+               msleep(10);
+       }
+
+       return retval;
+}
+
+static int             osc_ck_on;
+
+static int tusb_set_clock(struct clk *osc_ck, int state)
+{
+       if (state) {
+               if (osc_ck_on > 0)
+                       return -ENODEV;
+
+               omap2_block_sleep();
+               clk_enable(osc_ck);
+               osc_ck_on = 1;
+       } else {
+               if (osc_ck_on == 0)
+                       return -ENODEV;
+
+               clk_disable(osc_ck);
+               osc_ck_on = 0;
+               omap2_allow_sleep();
+       }
+
+       return 0;
+}
+
+void __init n800_usb_init(void)
+{
+       int ret = 0;
+       static char     announce[] __initdata = KERN_INFO "TUSB 6010\n";
+
+       /* PM companion chip power control pin */
+       ret = omap_request_gpio(GPIO_TUSB_ENABLE);
+       if (ret != 0) {
+               printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
+                      GPIO_TUSB_ENABLE);
+               return;
+       }
+       omap_set_gpio_direction(GPIO_TUSB_ENABLE, 0);
+
+       tusb_set_power(0);
+
+       ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
+                                       TUSB_ASYNC_CS, TUSB_SYNC_CS,
+                                       GPIO_TUSB_INT, 0x3f);
+       if (ret != 0)
+               goto err;
+
+       printk(announce);
+
+       return;
+
+err:
+       omap_free_gpio(GPIO_TUSB_ENABLE);
+}
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..2c64d2d
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800.c
+ *
+ * Copyright (C) 2005-2007 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+#include <linux/spi/tsc2005.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/lm8323.h>
+#include <linux/i2c/menelaus.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/gpio.h>
+#include <mach/usb.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/mcspi.h>
+#include <mach/lcd_mipid.h>
+#include <mach/clock.h>
+#include <mach/gpio-switch.h>
+#include <mach/omapfb.h>
+#include <mach/blizzard.h>
+
+#include <../drivers/cbus/tahvo.h>
+#include <../drivers/media/video/tcm825x.h>
+
+#define N800_BLIZZARD_POWERDOWN_GPIO   15
+#define N800_STI_GPIO                  62
+#define N800_KEYB_IRQ_GPIO             109
+#define N800_DAV_IRQ_GPIO              103
+#define N800_TSC2301_RESET_GPIO                118
+
+#ifdef CONFIG_MACH_NOKIA_N810
+static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = {
+       [0x01] = KEY_Q,
+       [0x02] = KEY_K,
+       [0x03] = KEY_O,
+       [0x04] = KEY_P,
+       [0x05] = KEY_BACKSPACE,
+       [0x06] = KEY_A,
+       [0x07] = KEY_S,
+       [0x08] = KEY_D,
+       [0x09] = KEY_F,
+       [0x0a] = KEY_G,
+       [0x0b] = KEY_H,
+       [0x0c] = KEY_J,
+
+       [0x11] = KEY_W,
+       [0x12] = KEY_F4,
+       [0x13] = KEY_L,
+       [0x14] = KEY_APOSTROPHE,
+       [0x16] = KEY_Z,
+       [0x17] = KEY_X,
+       [0x18] = KEY_C,
+       [0x19] = KEY_V,
+       [0x1a] = KEY_B,
+       [0x1b] = KEY_N,
+       [0x1c] = KEY_LEFTSHIFT, /* Actually, this is both shift keys */
+       [0x1f] = KEY_F7,
+
+       [0x21] = KEY_E,
+       [0x22] = KEY_SEMICOLON,
+       [0x23] = KEY_MINUS,
+       [0x24] = KEY_EQUAL,
+       [0x2b] = KEY_FN,
+       [0x2c] = KEY_M,
+       [0x2f] = KEY_F8,
+
+       [0x31] = KEY_R,
+       [0x32] = KEY_RIGHTCTRL,
+       [0x34] = KEY_SPACE,
+       [0x35] = KEY_COMMA,
+       [0x37] = KEY_UP,
+       [0x3c] = KEY_COMPOSE,
+       [0x3f] = KEY_F6,
+
+       [0x41] = KEY_T,
+       [0x44] = KEY_DOT,
+       [0x46] = KEY_RIGHT,
+       [0x4f] = KEY_F5,
+       [0x51] = KEY_Y,
+       [0x53] = KEY_DOWN,
+       [0x55] = KEY_ENTER,
+       [0x5f] = KEY_ESC,
+
+       [0x61] = KEY_U,
+       [0x64] = KEY_LEFT,
+
+       [0x71] = KEY_I,
+       [0x75] = KEY_KPENTER,
+};
+
+static struct lm8323_platform_data lm8323_pdata = {
+       .repeat = 0, /* Repeat is handled in userspace for now. */
+       .keymap = rx44_keymap,
+
+       .name = "Internal keyboard",
+       .pwm1_name = "keyboard",
+       .pwm2_name = "cover",
+};
+#endif
+
+void __init nokia_n800_init_irq(void)
+{
+       omap2_init_common_hw(NULL);
+       omap_init_irq();
+       omap_gpio_init();
+
+#ifdef CONFIG_OMAP_STI
+       if (omap_request_gpio(N800_STI_GPIO) < 0) {
+               printk(KERN_ERR "Failed to request GPIO %d for STI\n",
+                      N800_STI_GPIO);
+               return;
+       }
+
+       omap_set_gpio_direction(N800_STI_GPIO, 0);
+       omap_set_gpio_dataout(N800_STI_GPIO, 0);
+#endif
+}
+
+#if defined(CONFIG_MENELAUS) && defined(CONFIG_SENSORS_TMP105)
+
+static int n800_tmp105_set_power(int enable)
+{
+       return menelaus_set_vaux(enable ? 2800 : 0);
+}
+
+#else
+
+#define n800_tmp105_set_power NULL
+
+#endif
+
+static struct omap_uart_config n800_uart_config __initdata = {
+       .enabled_uarts = (1 << 0) | (1 << 2),
+};
+
+#include "../../../drivers/cbus/retu.h"
+
+static struct omap_fbmem_config n800_fbmem0_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem1_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_fbmem_config n800_fbmem2_config __initdata = {
+       .size = 752 * 1024,
+};
+
+static struct omap_tmp105_config n800_tmp105_config __initdata = {
+       .tmp105_irq_pin = 125,
+       .set_power = n800_tmp105_set_power,
+};
+
+static void mipid_shutdown(struct mipid_platform_data *pdata)
+{
+       if (pdata->nreset_gpio != -1) {
+               pr_info("shutdown LCD\n");
+               omap_set_gpio_dataout(pdata->nreset_gpio, 0);
+               msleep(120);
+       }
+}
+
+static struct mipid_platform_data n800_mipid_platform_data = {
+       .shutdown = mipid_shutdown,
+};
+
+static void __init mipid_dev_init(void)
+{
+       const struct omap_lcd_config *conf;
+
+       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (conf != NULL) {
+               n800_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
+               n800_mipid_platform_data.data_lines = conf->data_lines;
+       }
+}
+
+static struct {
+       struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+       blizzard.sys_ck = clk_get(0, "osc_ck");
+       if (IS_ERR(blizzard.sys_ck)) {
+               printk(KERN_ERR "can't get Blizzard clock\n");
+               return PTR_ERR(blizzard.sys_ck);
+       }
+       return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(struct device *dev)
+{
+       return clk_get_rate(blizzard.sys_ck);
+}
+
+static void blizzard_enable_clocks(int enable)
+{
+       if (enable)
+               clk_enable(blizzard.sys_ck);
+       else
+               clk_disable(blizzard.sys_ck);
+}
+
+static void blizzard_power_up(struct device *dev)
+{
+       /* Vcore to 1.475V */
+       tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+       msleep(10);
+
+       blizzard_enable_clocks(1);
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+       blizzard_enable_clocks(0);
+
+       /* Vcore to 1.005V */
+       tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static struct blizzard_platform_data n800_blizzard_data = {
+       .power_up       = blizzard_power_up,
+       .power_down     = blizzard_power_down,
+       .get_clock_rate = blizzard_get_clock_rate,
+       .te_connected   = 1,
+};
+
+static void __init blizzard_dev_init(void)
+{
+       int r;
+
+       r = omap_request_gpio(N800_BLIZZARD_POWERDOWN_GPIO);
+       if (r < 0)
+               return;
+       omap_set_gpio_direction(N800_BLIZZARD_POWERDOWN_GPIO, 0);
+       omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1);
+
+       blizzard_get_clocks();
+       omapfb_set_ctrl_platform_data(&n800_blizzard_data);
+}
+
+static struct omap_board_config_kernel n800_config[] __initdata = {
+       { OMAP_TAG_UART,                        &n800_uart_config },
+       { OMAP_TAG_FBMEM,                       &n800_fbmem0_config },
+       { OMAP_TAG_FBMEM,                       &n800_fbmem1_config },
+       { OMAP_TAG_FBMEM,                       &n800_fbmem2_config },
+       { OMAP_TAG_TMP105,                      &n800_tmp105_config },
+};
+
+static struct tsc2301_platform_data tsc2301_config = {
+       .reset_gpio     = N800_TSC2301_RESET_GPIO,
+       .keymap = {
+               -1,             /* Event for bit 0 */
+               KEY_UP,         /* Event for bit 1 (up) */
+               KEY_F5,         /* Event for bit 2 (home) */
+               -1,             /* Event for bit 3 */
+               KEY_LEFT,       /* Event for bit 4 (left) */
+               KEY_ENTER,      /* Event for bit 5 (enter) */
+               KEY_RIGHT,      /* Event for bit 6 (right) */
+               -1,             /* Event for bit 7 */
+               KEY_ESC,        /* Event for bit 8 (cycle) */
+               KEY_DOWN,       /* Event for bit 9 (down) */
+               KEY_F4,         /* Event for bit 10 (menu) */
+               -1,             /* Event for bit 11 */
+               KEY_F8,         /* Event for bit 12 (Zoom-) */
+               KEY_F6,         /* Event for bit 13 (FS) */
+               KEY_F7,         /* Event for bit 14 (Zoom+) */
+               -1,             /* Event for bit 15 */
+       },
+       .kp_rep         = 0,
+       .keyb_name      = "Internal keypad",
+};
+
+static void tsc2301_dev_init(void)
+{
+       int r;
+       int gpio = N800_KEYB_IRQ_GPIO;
+
+       r = gpio_request(gpio, "tsc2301 KBD IRQ");
+       if (r >= 0) {
+               gpio_direction_input(gpio);
+               tsc2301_config.keyb_int = OMAP_GPIO_IRQ(gpio);
+       } else {
+               printk(KERN_ERR "unable to get KBD GPIO");
+       }
+
+       gpio = N800_DAV_IRQ_GPIO;
+       r = gpio_request(gpio, "tsc2301 DAV IRQ");
+       if (r >= 0) {
+               gpio_direction_input(gpio);
+               tsc2301_config.dav_int = OMAP_GPIO_IRQ(gpio);
+       } else {
+               printk(KERN_ERR "unable to get DAV GPIO");
+       }
+}
+
+static int __init tea5761_dev_init(void)
+{
+       const struct omap_tea5761_config *info;
+       int enable_gpio = 0;
+
+       info = omap_get_config(OMAP_TAG_TEA5761, struct omap_tea5761_config);
+       if (info)
+               enable_gpio = info->enable_gpio;
+
+       if (enable_gpio) {
+               pr_debug("Enabling tea5761 at GPIO %d\n",
+                        enable_gpio);
+
+               if (omap_request_gpio(enable_gpio) < 0) {
+                       printk(KERN_ERR "Can't request GPIO %d\n",
+                              enable_gpio);
+                       return -ENODEV;
+               }
+
+               omap_set_gpio_direction(enable_gpio, 0);
+               udelay(50);
+               omap_set_gpio_dataout(enable_gpio, 1);
+       }
+
+       return 0;
+}
+
+static struct omap2_mcspi_device_config tsc2301_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config mipid_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,
+};
+
+static struct omap2_mcspi_device_config cx3110x_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,
+};
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+static struct tsc2005_platform_data tsc2005_config = {
+       .reset_gpio = 94,
+       .dav_gpio = 106
+};
+
+static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,
+};
+#endif
+
+static struct spi_board_info n800_spi_board_info[] __initdata = {
+       {
+               .modalias       = "lcd_mipid",
+               .bus_num        = 1,
+               .chip_select    = 1,
+               .max_speed_hz   = 4000000,
+               .controller_data= &mipid_mcspi_config,
+               .platform_data  = &n800_mipid_platform_data,
+       }, {
+               .modalias       = "cx3110x",
+               .bus_num        = 2,
+               .chip_select    = 0,
+               .max_speed_hz   = 48000000,
+               .controller_data= &cx3110x_mcspi_config,
+       },
+       {
+               .modalias       = "tsc2301",
+               .bus_num        = 1,
+               .chip_select    = 0,
+               .max_speed_hz   = 6000000,
+               .controller_data= &tsc2301_mcspi_config,
+               .platform_data  = &tsc2301_config,
+       },
+};
+
+static struct spi_board_info n810_spi_board_info[] __initdata = {
+       {
+               .modalias        = "lcd_mipid",
+               .bus_num         = 1,
+               .chip_select     = 1,
+               .max_speed_hz    = 4000000,
+               .controller_data = &mipid_mcspi_config,
+               .platform_data   = &n800_mipid_platform_data,
+       },
+       {
+               .modalias        = "cx3110x",
+               .bus_num         = 2,
+               .chip_select     = 0,
+               .max_speed_hz    = 48000000,
+               .controller_data = &cx3110x_mcspi_config,
+       },
+       {
+               .modalias        = "tsc2005",
+               .bus_num         = 1,
+               .chip_select     = 0,
+               .max_speed_hz    = 6000000,
+               .controller_data = &tsc2005_mcspi_config,
+               .platform_data   = &tsc2005_config,
+       },
+};
+
+static void __init tsc2005_set_config(void)
+{
+       const struct omap_lcd_config *conf;
+
+       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (conf != NULL) {
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+               if (strcmp(conf->panel_name, "lph8923") == 0) {
+                       tsc2005_config.ts_x_plate_ohm = 180;
+                       tsc2005_config.ts_hw_avg = 0;
+                       tsc2005_config.ts_ignore_last = 0;
+                       tsc2005_config.ts_touch_pressure = 1500;
+                       tsc2005_config.ts_stab_time = 100;
+                       tsc2005_config.ts_pressure_max = 2048;
+                       tsc2005_config.ts_pressure_fudge = 2;
+                       tsc2005_config.ts_x_max = 4096;
+                       tsc2005_config.ts_x_fudge = 4;
+                       tsc2005_config.ts_y_max = 4096;
+                       tsc2005_config.ts_y_fudge = 7;
+               } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+                       tsc2005_config.ts_x_plate_ohm = 280;
+                       tsc2005_config.ts_hw_avg = 0;
+                       tsc2005_config.ts_ignore_last = 0;
+                       tsc2005_config.ts_touch_pressure = 1500;
+                       tsc2005_config.ts_stab_time = 1000;
+                       tsc2005_config.ts_pressure_max = 2048;
+                       tsc2005_config.ts_pressure_fudge = 2;
+                       tsc2005_config.ts_x_max = 4096;
+                       tsc2005_config.ts_x_fudge = 4;
+                       tsc2005_config.ts_y_max = 4096;
+                       tsc2005_config.ts_y_fudge = 7;
+               } else {
+                       printk(KERN_ERR "Unknown panel type, set default "
+                              "touchscreen configuration\n");
+                       tsc2005_config.ts_x_plate_ohm = 200;
+                       tsc2005_config.ts_stab_time = 100;
+               }
+#endif
+       }
+}
+
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+
+void retu_keypad_led_set_power(struct omap_pwm_led_platform_data *self,
+                              int on_off)
+{
+       if (on_off) {
+               retu_write_reg(RETU_REG_CTRL_SET, 1 << 6);
+               msleep(2);
+               retu_write_reg(RETU_REG_CTRL_SET, 1 << 3);
+       } else {
+               retu_write_reg(RETU_REG_CTRL_CLR, (1 << 6) | (1 << 3));
+       }
+}
+
+static struct omap_pwm_led_platform_data n800_keypad_led_data = {
+       .name = "keypad",
+       .intensity_timer = 10,
+       .blink_timer = 9,
+       .set_power = retu_keypad_led_set_power,
+};
+
+static struct platform_device n800_keypad_led_device = {
+       .name           = "omap_pwm_led",
+       .id             = -1,
+       .dev            = {
+               .platform_data = &n800_keypad_led_data,
+       },
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_TSC2301)
+static void __init n800_ts_set_config(void)
+{
+       const struct omap_lcd_config *conf;
+
+       conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+       if (conf != NULL) {
+               if (strcmp(conf->panel_name, "lph8923") == 0) {
+                       tsc2301_config.ts_x_plate_ohm   = 180;
+                       tsc2301_config.ts_hw_avg        = 8;
+                       tsc2301_config.ts_max_pressure  = 2048;
+                       tsc2301_config.ts_touch_pressure = 400;
+                       tsc2301_config.ts_stab_time     = 100;
+                       tsc2301_config.ts_pressure_fudge = 2;
+                       tsc2301_config.ts_x_max         = 4096;
+                       tsc2301_config.ts_x_fudge       = 4;
+                       tsc2301_config.ts_y_max         = 4096;
+                       tsc2301_config.ts_y_fudge       = 7;
+               } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+                       tsc2301_config.ts_x_plate_ohm   = 280;
+                       tsc2301_config.ts_hw_avg        = 8;
+                       tsc2301_config.ts_touch_pressure = 400;
+                       tsc2301_config.ts_max_pressure  = 2048;
+                       tsc2301_config.ts_stab_time     = 1000;
+                       tsc2301_config.ts_pressure_fudge = 2;
+                       tsc2301_config.ts_x_max         = 4096;
+                       tsc2301_config.ts_x_fudge       = 4;
+                       tsc2301_config.ts_y_max         = 4096;
+                       tsc2301_config.ts_y_fudge       = 7;
+               } else {
+                       printk(KERN_ERR "Unknown panel type, set default "
+                              "touchscreen configuration\n");
+                       tsc2301_config.ts_x_plate_ohm   = 200;
+                       tsc2301_config.ts_stab_time     = 100;
+               }
+       }
+}
+#else
+static inline void n800_ts_set_config(void)
+{
+}
+#endif
+
+static struct omap_gpio_switch n800_gpio_switches[] __initdata = {
+       {
+               .name                   = "bat_cover",
+               .gpio                   = -1,
+               .debounce_rising        = 100,
+               .debounce_falling       = 0,
+               .notify                 = n800_mmc_slot1_cover_handler,
+               .notify_data            = NULL,
+       }, {
+               .name                   = "headphone",
+               .gpio                   = -1,
+               .debounce_rising        = 200,
+               .debounce_falling       = 200,
+       }, {
+               .name                   = "cam_act",
+               .gpio                   = -1,
+               .debounce_rising        = 200,
+               .debounce_falling       = 200,
+       }, {
+               .name                   = "cam_turn",
+               .gpio                   = -1,
+               .debounce_rising        = 100,
+               .debounce_falling       = 100,
+       },
+};
+
+static struct platform_device *n800_devices[] __initdata = {
+#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM)
+       &n800_keypad_led_device,
+#endif
+};
+
+#ifdef CONFIG_MENELAUS
+static int n800_auto_sleep_regulators(void)
+{
+       u32 val;
+       int ret;
+
+       val = EN_VPLL_SLEEP | EN_VMMC_SLEEP    \
+               | EN_VAUX_SLEEP | EN_VIO_SLEEP \
+               | EN_VMEM_SLEEP | EN_DC3_SLEEP \
+               | EN_VC_SLEEP | EN_DC2_SLEEP;
+
+       ret = menelaus_set_regulator_sleep(1, val);
+       if (ret < 0) {
+               printk(KERN_ERR "Could not set regulators to sleep on "
+                       "menelaus: %u\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int n800_auto_voltage_scale(void)
+{
+       int ret;
+
+       ret = menelaus_set_vcore_hw(1400, 1050);
+       if (ret < 0) {
+               printk(KERN_ERR "Could not set VCORE voltage on "
+                       "menelaus: %u\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int n800_menelaus_init(struct device *dev)
+{
+       int ret;
+
+       ret = n800_auto_voltage_scale();
+       if (ret < 0)
+               return ret;
+       ret = n800_auto_sleep_regulators();
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static struct menelaus_platform_data n800_menelaus_platform_data = {
+       .late_init = n800_menelaus_init,
+};
+#endif
+
+static struct i2c_board_info __initdata n800_i2c_board_info_1[] = {
+       {
+               I2C_BOARD_INFO("menelaus", 0x72),
+               .irq = INT_24XX_SYS_NIRQ,
+               .platform_data = &n800_menelaus_platform_data,
+       },
+};
+
+extern struct tcm825x_platform_data n800_tcm825x_platform_data;
+
+static struct i2c_board_info __initdata_or_module n8x0_i2c_board_info_2[] = {
+       {
+               I2C_BOARD_INFO(TCM825X_NAME, TCM825X_I2C_ADDR),
+#if defined (CONFIG_VIDEO_TCM825X) || defined (CONFIG_VIDEO_TCM825X_MODULE)
+               .platform_data = &n800_tcm825x_platform_data,
+#endif
+       },
+};
+
+
+static struct i2c_board_info __initdata_or_module n800_i2c_board_info_2[] = {
+       {
+               I2C_BOARD_INFO("tea5761", 0x10),
+       },
+};
+
+static struct i2c_board_info __initdata_or_module n810_i2c_board_info_2[] = {
+       {
+               I2C_BOARD_INFO("lm8323", 0x45),
+               .irq            = OMAP_GPIO_IRQ(109),
+               .platform_data  = &lm8323_pdata,
+       },
+       {
+               I2C_BOARD_INFO("tsl2563", 0x29),
+       },
+       {
+               I2C_BOARD_INFO("lp5521", 0x32),
+       },
+};
+
+void __init nokia_n800_common_init(void)
+{
+       platform_add_devices(n800_devices, ARRAY_SIZE(n800_devices));
+
+       n800_flash_init();
+       n800_mmc_init();
+       n800_bt_init();
+       n800_dsp_init();
+       n800_usb_init();
+       n800_cam_init();
+       if (machine_is_nokia_n800())
+               spi_register_board_info(n800_spi_board_info,
+                               ARRAY_SIZE(n800_spi_board_info));
+       if (machine_is_nokia_n810()) {
+               tsc2005_set_config();
+               spi_register_board_info(n810_spi_board_info,
+                               ARRAY_SIZE(n810_spi_board_info));
+       }
+       omap_serial_init();
+       omap_register_i2c_bus(1, 400, n800_i2c_board_info_1,
+                             ARRAY_SIZE(n800_i2c_board_info_1));
+       omap_register_i2c_bus(2, 400, n8x0_i2c_board_info_2,
+                             ARRAY_SIZE(n8x0_i2c_board_info_2));
+       if (machine_is_nokia_n800())
+               i2c_register_board_info(2, n800_i2c_board_info_2,
+                       ARRAY_SIZE(n800_i2c_board_info_2));
+       if (machine_is_nokia_n810())
+               i2c_register_board_info(2, n810_i2c_board_info_2,
+                       ARRAY_SIZE(n810_i2c_board_info_2));
+               
+       mipid_dev_init();
+       blizzard_dev_init();
+}
+
+static void __init nokia_n800_init(void)
+{
+       nokia_n800_common_init();
+
+       n800_audio_init(&tsc2301_config);
+       n800_ts_set_config();
+       tsc2301_dev_init();
+       tea5761_dev_init();
+       omap_register_gpio_switches(n800_gpio_switches,
+                                   ARRAY_SIZE(n800_gpio_switches));
+}
+
+void __init nokia_n800_map_io(void)
+{
+       omap_board_config = n800_config;
+       omap_board_config_size = ARRAY_SIZE(n800_config);
+
+       omap2_set_globals_242x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(NOKIA_N800, "Nokia N800")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = nokia_n800_map_io,
+       .init_irq       = nokia_n800_init_irq,
+       .init_machine   = nokia_n800_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-n800.h b/arch/arm/mach-omap2/board-n800.h
new file mode 100644 (file)
index 0000000..e71dae4
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n800.h
+ *
+ * Copyright (C) 2005-2007 Nokia Corporation
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * Modified from mach-omap2/board-n800.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_BOARD_N800_H
+#define __ARCH_ARM_MACH_OMAP2_BOARD_N800_H
+
+void __init nokia_n800_common_init(void);
+void __init nokia_n800_map_io(void);
+void __init nokia_n800_init_irq(void);
+
+extern const struct tcm825x_platform_data n800_tcm825x_platform_data;
+
+#endif
diff --git a/arch/arm/mach-omap2/board-n810.c b/arch/arm/mach-omap2/board-n810.c
new file mode 100644 (file)
index 0000000..7984d43
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n810.c
+ *
+ * Copyright (C) 2007 Nokia
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/lm8323.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/board.h>
+#include <mach/common.h>
+
+#include "board-n800.h"
+
+static void __init nokia_n810_init(void)
+{
+       nokia_n800_common_init();
+}
+
+MACHINE_START(NOKIA_N810, "Nokia N810")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = nokia_n800_map_io,
+       .init_irq       = nokia_n800_init_irq,
+       .init_machine   = nokia_n810_init,
+       .timer          = &omap_timer,
+MACHINE_END
+
+MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = nokia_n800_map_io,
+       .init_irq       = nokia_n800_init_irq,
+       .init_machine   = nokia_n810_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
new file mode 100644 (file)
index 0000000..9f19c34
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap2evm.c
+ *
+ * Copyright (C) 2008 Mistral Solutions Pvt Ltd
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/hsmmc.h>
+#include <mach/keypad.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+#define GPMC_OFF_CONFIG1_0 0x60
+
+static struct mtd_partition omap2evm_nand_partitions[] = {
+       {
+               .name           = "X-Loader",
+               .offset         = 0,
+               .size           = 1 * (64 * 2048),
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 3 * (64 * 2048),
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot Environment",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1 * (64 * 2048),
+        },
+       {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 16 * (64 * 2048),     /* 2MB */
+       },
+       {
+               .name           = "Ramdisk",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 32 * (64 * 2048),     /* 4MB */
+       },
+       {
+               .name           = "Filesystem",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       }
+};
+
+static struct omap_nand_platform_data omap2evm_nand_data = {
+       .parts          = omap2evm_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(omap2evm_nand_partitions),
+       .dma_channel    = -1,   /* disable DMA in OMAP NAND driver */
+};
+
+static struct resource omap2evm_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device omap2evm_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &omap2evm_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &omap2evm_nand_resource,
+};
+
+void __init omap2evm_flash_init(void)
+{
+       void __iomem *gpmc_base_add, *gpmc_cs_base_add;
+       unsigned char cs = 0;
+
+       gpmc_base_add = (__force void __iomem *)OMAP243X_GPMC_VIRT;
+       while (cs < GPMC_CS_NUM) {
+               int ret = 0;
+
+               /* Each GPMC set for a single CS is at offset 0x30 */
+               gpmc_cs_base_add = (gpmc_base_add + GPMC_OFF_CONFIG1_0 +
+                                   (cs * 0x30));
+
+               /* xloader/Uboot would have programmed the NAND
+                * base address for us This is a ugly hack. The proper
+                * way of doing this is to pass the setup of u-boot up
+                * to kernel using kernel params - something on the
+                * lines of machineID. Check if Nand is
+                * configured */
+               ret = __raw_readl(gpmc_cs_base_add + GPMC_CS_CONFIG1);
+               if ((ret & 0xC00) == (0x800)) {
+                       /* Found it!! */
+                       printk(KERN_INFO "NAND: Found NAND on CS %d \n", cs);
+                       break;
+               }
+               cs++;
+       }
+       if (cs >= GPMC_CS_NUM) {
+               printk(KERN_INFO "MTD: Unable to find MTD configuration in "
+                                "GPMC   - not registering.\n");
+               return;
+       }
+
+       omap2evm_nand_data.cs                   = cs;
+       omap2evm_nand_data.gpmc_cs_baseaddr     = gpmc_cs_base_add;
+       omap2evm_nand_data.gpmc_baseaddr        = gpmc_base_add;
+
+       if (platform_device_register(&omap2evm_nand_device) < 0) {
+               printk(KERN_ERR "Unable to register NAND device\n");
+               return;
+       }
+}
+
+static struct resource omap2evm_smc911x_resources[] = {
+       [0] =   {
+               .start  = OMAP2EVM_ETHR_START,
+               .end    = (OMAP2EVM_ETHR_START + OMAP2EVM_ETHR_SIZE - 1),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] =   {
+               .start  = OMAP_GPIO_IRQ(OMAP2EVM_ETHR_GPIO_IRQ),
+               .end    = OMAP_GPIO_IRQ(OMAP2EVM_ETHR_GPIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap2evm_smc911x_device = {
+       .name       = "smc911x",
+       .id     = -1,
+       .num_resources  = ARRAY_SIZE(omap2evm_smc911x_resources),
+       .resource   = &omap2evm_smc911x_resources [0],
+};
+
+static inline void __init omap2evm_init_smc911x(void)
+{
+       int gpio = OMAP2EVM_ETHR_GPIO_IRQ;
+       int ret;
+
+       ret = gpio_request(gpio, "smc911x IRQ");
+       if (ret < 0) {
+               printk(KERN_ERR "Failed to request GPIO %d for smc911x IRQ\n",
+                               gpio);
+               return;
+       }
+       gpio_direction_input(gpio);
+
+}
+
+static struct platform_device omap2_evm_lcd_device = {
+       .name           = "omap2evm_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap2_evm_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static int omap2evm_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap2evm_kp_data = {
+       .rows           = 4,
+       .cols           = 4,
+       .keymap         = omap2evm_keymap,
+       .keymapsize     = ARRAY_SIZE(omap2evm_keymap),
+       .rep            = 1,
+       .irq            = TWL4030_MODIRQ_KEYPAD,
+};
+
+static void __init omap2_evm_init_irq(void)
+{
+       omap2_init_common_hw(NULL);
+       omap_init_irq();
+       omap_gpio_init();
+       omap2evm_init_smc911x();
+}
+
+static struct omap_uart_config omap2_evm_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap2_evm_uart_config },
+       { OMAP_TAG_LCD,         &omap2_evm_lcd_config },
+};
+
+static struct twl4030_gpio_platform_data omap2evm_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data omap2evm_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_madc_platform_data omap2evm_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data omap2evm_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .keypad         = &omap2evm_kp_data,
+       .madc           = &omap2evm_madc_data,
+       .usb            = &omap2evm_usb_data,
+       .gpio           = &omap2evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_24XX_SYS_NIRQ,
+               .platform_data = &omap2evm_twldata,
+       },
+};
+
+static int __init omap2_evm_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 400, NULL, 0);
+       omap_register_i2c_bus(2, 2600, omap2evm_i2c_boardinfo,
+                       ARRAY_SIZE(omap2evm_i2c_boardinfo));
+       return 0;
+}
+
+static struct platform_device *omap2_evm_devices[] __initdata = {
+       &omap2_evm_lcd_device,
+       &omap2evm_smc911x_device,
+};
+
+static void __init omap2_evm_init(void)
+{
+       omap2_evm_i2c_init();
+
+       platform_add_devices(omap2_evm_devices, ARRAY_SIZE(omap2_evm_devices));
+       omap_board_config = omap2_evm_config;
+       omap_board_config_size = ARRAY_SIZE(omap2_evm_config);
+       omap_serial_init();
+       hsmmc_init();
+       omap2evm_flash_init();
+}
+
+static void __init omap2_evm_map_io(void)
+{
+       omap2_set_globals_243x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP2EVM, "OMAP2EVM Board")
+       /* Maintainer:  Arun KS <arunks@mistralsolutions.com> */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap2_evm_map_io,
+       .init_irq       = omap2_evm_init_irq,
+       .init_machine   = omap2_evm_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
new file mode 100644 (file)
index 0000000..19702c7
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3beagle.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+#include <linux/i2c/twl4030.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/flash.h>
+
+#include <mach/board.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
+#include <mach/hsmmc.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+#include <mach/mux.h>
+
+
+#define GPMC_CS0_BASE  0x60
+#define GPMC_CS_SIZE   0x30
+
+#define NAND_BLOCK_SIZE                SZ_128K
+
+static struct mtd_partition omap3beagle_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+               .name           = "X-Loader",
+               .offset         = 0,
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 15 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot Env",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x260000 */
+               .size           = 1 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "Kernel",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "File System",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data omap3beagle_nand_data = {
+       .options        = NAND_BUSWIDTH_16,
+       .parts          = omap3beagle_nand_partitions,
+       .nr_parts       = ARRAY_SIZE(omap3beagle_nand_partitions),
+       .dma_channel    = -1,           /* disable DMA in OMAP NAND driver */
+       .nand_setup     = NULL,
+       .dev_ready      = NULL,
+};
+
+static struct resource omap3beagle_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device omap3beagle_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &omap3beagle_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &omap3beagle_nand_resource,
+};
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+
+static struct omap_uart_config omap3_beagle_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct twl4030_usb_data beagle_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static int beagle_twl_gpio_setup(struct device *dev,
+               unsigned gpio, unsigned ngpio)
+{
+       /* request_gpio(gpio + 0, "mmc0_cd");
+        * gpio_direction_input(gpio + 0);
+        */
+
+       gpio_request(gpio + 1, "EHCI_nOC");
+       gpio_direction_input(gpio + 1);
+
+       /* gpio + 18 + 0 == ledA, nEN_USB_PWR (out)
+        * gpio + 18 + 1 == ledB, PMU_STAT (out, a LED)
+        */
+
+       return 0;
+}
+
+static struct twl4030_gpio_platform_data beagle_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+       .pullups        = BIT(1),
+       .pulldowns      = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
+                               | BIT(15) | BIT(16) | BIT(17),
+       .setup          = beagle_twl_gpio_setup,
+};
+
+static struct twl4030_platform_data beagle_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .usb            = &beagle_usb_data,
+       .gpio           = &beagle_gpio_data,
+};
+
+static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &beagle_twldata,
+       },
+};
+
+static int __init omap3_beagle_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
+                       ARRAY_SIZE(beagle_i2c_boardinfo));
+#ifdef CONFIG_I2C2_OMAP_BEAGLE
+       omap_register_i2c_bus(2, 400, NULL, 0);
+#endif
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init omap3_beagle_init_irq(void)
+{
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct platform_device omap3_beagle_lcd_device = {
+       .name           = "omap3beagle_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3_beagle_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct gpio_led gpio_leds[] = {
+       {
+               .name                   = "beagleboard::usr0",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 150,
+       },
+       {
+               .name                   = "beagleboard::usr1",
+               .default_trigger        = "mmc0",
+               .gpio                   = 149,
+       },
+};
+
+static struct gpio_led_platform_data gpio_led_info = {
+       .leds           = gpio_leds,
+       .num_leds       = ARRAY_SIZE(gpio_leds),
+};
+
+static struct platform_device leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_led_info,
+       },
+};
+
+static struct gpio_keys_button gpio_buttons[] = {
+       {
+               .code                   = BTN_EXTRA,
+               .gpio                   = 7,
+               .desc                   = "user",
+               .wakeup                 = 1,
+       },
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+       .buttons        = gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device keys_gpio = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &gpio_key_info,
+       },
+};
+
+static struct omap_board_config_kernel omap3_beagle_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3_beagle_uart_config },
+       { OMAP_TAG_LCD,         &omap3_beagle_lcd_config },
+};
+
+static struct platform_device *omap3_beagle_devices[] __initdata = {
+       &omap3_beagle_lcd_device,
+       &leds_gpio,
+       &keys_gpio,
+};
+
+static void __init omap3beagle_flash_init(void)
+{
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+
+       u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+       /* find out the chip-select on which NAND exists */
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               if ((ret & 0xC00) == 0x800) {
+                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               }
+               cs++;
+       }
+
+       if (nandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "NAND: Unable to find configuration "
+                                "in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               omap3beagle_nand_data.cs = nandcs;
+               omap3beagle_nand_data.gpmc_cs_baseaddr = (void *)
+                       (gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
+               omap3beagle_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+               if (platform_device_register(&omap3beagle_nand_device) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+}
+
+static void __init omap3_beagle_init(void)
+{
+       omap3_beagle_i2c_init();
+       platform_add_devices(omap3_beagle_devices,
+                       ARRAY_SIZE(omap3_beagle_devices));
+       omap_board_config = omap3_beagle_config;
+       omap_board_config_size = ARRAY_SIZE(omap3_beagle_config);
+       omap_serial_init();
+
+       omap_cfg_reg(AH8_34XX_GPIO29);
+       gpio_request(29, "mmc0_wp");
+       gpio_direction_input(29);
+       hsmmc_init();
+
+       omap_cfg_reg(J25_34XX_GPIO170);
+       gpio_request(170, "DVI_nPD");
+       /* REVISIT leave DVI powered down until it's needed ... */
+       gpio_direction_output(170, true);
+
+       usb_musb_init();
+       usb_ehci_init();
+       omap3beagle_flash_init();
+}
+
+static void __init omap3_beagle_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
+       /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_beagle_map_io,
+       .init_irq       = omap3_beagle_init_irq,
+       .init_machine   = omap3_beagle_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-omap3evm-flash.c b/arch/arm/mach-omap2/board-omap3evm-flash.c
new file mode 100644 (file)
index 0000000..5f3663d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * board-omap3evm-flash.c
+ *
+ * Copyright (c) 2008 Texas Instruments,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include <asm/mach/flash.h>
+#include <mach/onenand.h>
+#include <mach/board.h>
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+static int omap3evm_onenand_setup(void __iomem *, int freq);
+
+static struct mtd_partition omap3evm_onenand_partitions[] = {
+       {
+               .name           = "xloader",
+               .offset         = 0,
+               .size           = 4*(64*2048),
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "uboot",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           =  15*(64*2048),
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "params",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 1*(64*2048),
+       },
+       {
+               .name           = "linux",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 40*(64*2048),
+       },
+       {
+               .name           = "jffs2",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_onenand_platform_data omap3evm_onenand_data = {
+       .parts = omap3evm_onenand_partitions,
+       .nr_parts = ARRAY_SIZE(omap3evm_onenand_partitions),
+       .onenand_setup = omap3evm_onenand_setup,
+       .dma_channel    = -1,   /* disable DMA in OMAP OneNAND driver */
+};
+
+static struct platform_device omap3evm_onenand_device = {
+       .name           = "omap2-onenand",
+       .id             = -1,
+       .dev = {
+               .platform_data = &omap3evm_onenand_data,
+       },
+};
+
+/*
+ *      omap3evm_onenand_setup - Set the onenand sync mode
+ *      @onenand_base:  The onenand base address in GPMC memory map
+ *
+ */
+
+static int omap3evm_onenand_setup(void __iomem *onenand_base, int freq)
+{
+       /* nothing is required to be setup for onenand as of now */
+       return 0;
+}
+
+void __init omap3evm_flash_init(void)
+{
+       u8              cs = 0;
+       u8              onenandcs = GPMC_CS_NUM + 1;
+
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+
+               /*
+               * xloader/Uboot would have programmed the oneNAND
+               * base address for us This is a ugly hack. The proper
+               * way of doing this is to pass the setup of u-boot up
+               * to kernel using kernel params - something on the
+               * lines of machineID. Check if oneNAND is configured
+               */
+               if ((ret & 0x3F) == (ONENAND_MAP >> 24))
+                       onenandcs = cs;
+               cs++;
+       }
+       if (onenandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "OneNAND: Unable to find configuration "
+                               " in GPMC\n ");
+               return;
+       }
+
+       if (onenandcs < GPMC_CS_NUM) {
+               omap3evm_onenand_data.cs = onenandcs;
+               if (platform_device_register(&omap3evm_onenand_device) < 0)
+                       printk(KERN_ERR "Unable to register OneNAND device\n");
+       }
+}
+
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
new file mode 100644 (file)
index 0000000..3538067
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * linux/arch/arm/mach-omap2/board-omap3evm.c
+ *
+ * Copyright (C) 2008 Texas Instruments
+ *
+ * Modified from mach-omap2/board-3430sdp.c
+ *
+ * Initial code: Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/input.h>
+
+#include <linux/i2c/twl4030.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/gpio.h>
+#include <mach/keypad.h>
+#include <mach/board.h>
+#include <mach/hsmmc.h>
+#include <mach/usb-musb.h>
+#include <mach/usb-ehci.h>
+#include <mach/common.h>
+#include <mach/mcspi.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+
+static struct resource omap3evm_smc911x_resources[] = {
+       [0] =   {
+               .start  = OMAP3EVM_ETHR_START,
+               .end    = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] =   {
+               .start  = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+               .end    = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device omap3evm_smc911x_device = {
+       .name           = "smc911x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap3evm_smc911x_resources),
+       .resource       = &omap3evm_smc911x_resources [0],
+};
+
+static inline void __init omap3evm_init_smc911x(void)
+{
+       int eth_cs;
+       struct clk *l3ck;
+       unsigned int rate;
+
+       eth_cs = OMAP3EVM_SMC911X_CS;
+
+       l3ck = clk_get(NULL, "l3_ck");
+       if (IS_ERR(l3ck))
+               rate = 100000000;
+       else
+               rate = clk_get_rate(l3ck);
+
+       if (omap_request_gpio(OMAP3EVM_ETHR_GPIO_IRQ) < 0) {
+               printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+                       OMAP3EVM_ETHR_GPIO_IRQ);
+               return;
+       }
+
+       omap_set_gpio_direction(OMAP3EVM_ETHR_GPIO_IRQ, 1);
+}
+
+static struct omap_uart_config omap3_evm_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data omap3evm_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static int omap3evm_keymap[] = {
+       KEY(0, 0, KEY_LEFT),
+       KEY(0, 1, KEY_RIGHT),
+       KEY(0, 2, KEY_A),
+       KEY(0, 3, KEY_B),
+       KEY(1, 0, KEY_DOWN),
+       KEY(1, 1, KEY_UP),
+       KEY(1, 2, KEY_E),
+       KEY(1, 3, KEY_F),
+       KEY(2, 0, KEY_ENTER),
+       KEY(2, 1, KEY_I),
+       KEY(2, 2, KEY_J),
+       KEY(2, 3, KEY_K),
+       KEY(3, 0, KEY_M),
+       KEY(3, 1, KEY_N),
+       KEY(3, 2, KEY_O),
+       KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+       .rows           = 4,
+       .cols           = 4,
+       .keymap         = omap3evm_keymap,
+       .keymapsize     = ARRAY_SIZE(omap3evm_keymap),
+       .rep            = 1,
+       .irq            = TWL4030_MODIRQ_KEYPAD,
+};
+
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+       .irq_line       = 1,
+};
+
+static struct twl4030_platform_data omap3evm_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+
+       /* platform_data for children goes here */
+       .keypad         = &omap3evm_kp_data,
+       .madc           = &omap3evm_madc_data,
+       .usb            = &omap3evm_usb_data,
+       .gpio           = &omap3evm_gpio_data,
+};
+
+static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &omap3evm_twldata,
+       },
+};
+
+static int __init omap3_evm_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
+                       ARRAY_SIZE(omap3evm_i2c_boardinfo));
+       omap_register_i2c_bus(2, 400, NULL, 0);
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static struct platform_device omap3_evm_lcd_device = {
+       .name           = "omap3evm_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config omap3_evm_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static void ads7846_dev_init(void)
+{
+       if (omap_request_gpio(OMAP3_EVM_TS_GPIO) < 0)
+               printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
+
+       omap_set_gpio_direction(OMAP3_EVM_TS_GPIO, 1);
+
+       omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
+       omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+}
+
+static int ads7846_get_pendown_state(void)
+{
+       return !omap_get_gpio_datain(OMAP3_EVM_TS_GPIO);
+}
+
+struct ads7846_platform_data ads7846_config = {
+       .x_max                  = 0x0fff,
+       .y_max                  = 0x0fff,
+       .x_plate_ohms           = 180,
+       .pressure_max           = 255,
+       .debounce_max           = 10,
+       .debounce_tol           = 3,
+       .debounce_rep           = 1,
+       .get_pendown_state      = ads7846_get_pendown_state,
+       .keep_vref_on           = 1,
+       .settle_delay_usecs     = 150,
+};
+
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+       .turbo_mode     = 0,
+       .single_channel = 1,  /* 0: slave, 1: master */
+};
+
+struct spi_board_info omap3evm_spi_board_info[] = {
+       [0] = {
+               .modalias               = "ads7846",
+               .bus_num                = 1,
+               .chip_select            = 0,
+               .max_speed_hz           = 1500000,
+               .controller_data        = &ads7846_mcspi_config,
+               .irq                    = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
+               .platform_data          = &ads7846_config,
+       },
+};
+
+static void __init omap3_evm_init_irq(void)
+{
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+       omap3evm_init_smc911x();
+}
+
+static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
+       { OMAP_TAG_UART,        &omap3_evm_uart_config },
+       { OMAP_TAG_LCD,         &omap3_evm_lcd_config },
+};
+
+static struct platform_device *omap3_evm_devices[] __initdata = {
+       &omap3_evm_lcd_device,
+       &omap3evm_smc911x_device,
+};
+
+static void __init omap3_evm_init(void)
+{
+       omap3_evm_i2c_init();
+
+       platform_add_devices(omap3_evm_devices, ARRAY_SIZE(omap3_evm_devices));
+       omap_board_config = omap3_evm_config;
+       omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
+
+       spi_register_board_info(omap3evm_spi_board_info,
+                               ARRAY_SIZE(omap3evm_spi_board_info));
+
+       omap_serial_init();
+       hsmmc_init();
+       usb_musb_init();
+       usb_ehci_init();
+       omap3evm_flash_init();
+       ads7846_dev_init();
+}
+
+static void __init omap3_evm_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OMAP3EVM, "OMAP3 EVM")
+       /* Maintainer: Syed Mohammed Khasim - Texas Instruments */
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = omap3_evm_map_io,
+       .init_irq       = omap3_evm_init_irq,
+       .init_machine   = omap3_evm_init,
+       .timer          = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
new file mode 100644 (file)
index 0000000..4e2781a
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * board-overo.c (Gumstix Overo)
+ *
+ * Initial code: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c/twl4030.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-overo.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpio.h>
+#include <mach/gpmc.h>
+#include <mach/hardware.h>
+#include <mach/hsmmc.h>
+#include <mach/nand.h>
+#include <mach/usb-ehci.h>
+#include <mach/usb-musb.h>
+
+#include "sdram-micron-mt46h32m32lf-6.h"
+
+#define NAND_BLOCK_SIZE SZ_128K
+#define GPMC_CS0_BASE  0x60
+#define GPMC_CS_SIZE   0x30
+
+static struct mtd_partition overo_nand_partitions[] = {
+       {
+               .name           = "xloader",
+               .offset         = 0,                    /* Offset = 0x00000 */
+               .size           = 4 * NAND_BLOCK_SIZE,
+               .mask_flags     = MTD_WRITEABLE
+       },
+       {
+               .name           = "uboot",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 14 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "uboot environment",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x240000 */
+               .size           = 2 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "linux",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x280000 */
+               .size           = 32 * NAND_BLOCK_SIZE,
+       },
+       {
+               .name           = "rootfs",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x680000 */
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct omap_nand_platform_data overo_nand_data = {
+       .parts = overo_nand_partitions,
+       .nr_parts = ARRAY_SIZE(overo_nand_partitions),
+       .dma_channel = -1,      /* disable DMA in OMAP NAND driver */
+};
+
+static struct resource overo_nand_resource = {
+       .flags          = IORESOURCE_MEM,
+};
+
+static struct platform_device overo_nand_device = {
+       .name           = "omap2-nand",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &overo_nand_data,
+       },
+       .num_resources  = 1,
+       .resource       = &overo_nand_resource,
+};
+
+
+static void __init overo_flash_init(void)
+{
+       u8 cs = 0;
+       u8 nandcs = GPMC_CS_NUM + 1;
+
+       u32 gpmc_base_add = OMAP34XX_GPMC_VIRT;
+
+       /* find out the chip-select on which NAND exists */
+       while (cs < GPMC_CS_NUM) {
+               u32 ret = 0;
+               ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+               if ((ret & 0xC00) == 0x800) {
+                       printk(KERN_INFO "Found NAND on CS%d\n", cs);
+                       if (nandcs > GPMC_CS_NUM)
+                               nandcs = cs;
+               }
+               cs++;
+       }
+
+       if (nandcs > GPMC_CS_NUM) {
+               printk(KERN_INFO "NAND: Unable to find configuration "
+                                "in GPMC\n ");
+               return;
+       }
+
+       if (nandcs < GPMC_CS_NUM) {
+               overo_nand_data.cs = nandcs;
+               overo_nand_data.gpmc_cs_baseaddr = (void *)
+                       (gpmc_base_add + GPMC_CS0_BASE + nandcs * GPMC_CS_SIZE);
+               overo_nand_data.gpmc_baseaddr = (void *) (gpmc_base_add);
+
+               printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+               if (platform_device_register(&overo_nand_device) < 0)
+                       printk(KERN_ERR "Unable to register NAND device\n");
+       }
+}
+static struct omap_uart_config overo_uart_config __initdata = {
+       .enabled_uarts  = ((1 << 0) | (1 << 1) | (1 << 2)),
+};
+static struct twl4030_gpio_platform_data overo_gpio_data = {
+       .gpio_base      = OMAP_MAX_GPIO_LINES,
+       .irq_base       = TWL4030_GPIO_IRQ_BASE,
+       .irq_end        = TWL4030_GPIO_IRQ_END,
+};
+
+static struct twl4030_usb_data overo_usb_data = {
+       .usb_mode       = T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_platform_data overo_twldata = {
+       .irq_base       = TWL4030_IRQ_BASE,
+       .irq_end        = TWL4030_IRQ_END,
+       .gpio           = &overo_gpio_data,
+       .usb            = &overo_usb_data,
+};
+
+static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
+       {
+               I2C_BOARD_INFO("twl4030", 0x48),
+               .flags = I2C_CLIENT_WAKE,
+               .irq = INT_34XX_SYS_NIRQ,
+               .platform_data = &overo_twldata,
+       },
+};
+
+static int __init overo_i2c_init(void)
+{
+       omap_register_i2c_bus(1, 2600, overo_i2c_boardinfo,
+                       ARRAY_SIZE(overo_i2c_boardinfo));
+       /* i2c2 pins are used for gpio */
+       omap_register_i2c_bus(3, 400, NULL, 0);
+       return 0;
+}
+
+static void __init overo_init_irq(void)
+{
+       omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
+       omap_init_irq();
+       omap_gpio_init();
+}
+
+static struct platform_device overo_lcd_device = {
+       .name           = "overo_lcd",
+       .id             = -1,
+};
+
+static struct omap_lcd_config overo_lcd_config __initdata = {
+       .ctrl_name      = "internal",
+};
+
+static struct omap_board_config_kernel overo_config[] __initdata = {
+       { OMAP_TAG_UART,        &overo_uart_config },
+       { OMAP_TAG_LCD,         &overo_lcd_config },
+};
+
+static struct platform_device *overo_devices[] __initdata = {
+       &overo_lcd_device,
+};
+
+static void __init overo_init(void)
+{
+       overo_i2c_init();
+       platform_add_devices(overo_devices, ARRAY_SIZE(overo_devices));
+       omap_board_config = overo_config;
+       omap_board_config_size = ARRAY_SIZE(overo_config);
+       omap_serial_init();
+       hsmmc_init();
+       usb_musb_init();
+       usb_ehci_init();
+       overo_flash_init();
+
+       if ((gpio_request(OVERO_GPIO_W2W_NRESET,
+                         "OVERO_GPIO_W2W_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) {
+               gpio_export(OVERO_GPIO_W2W_NRESET, 0);
+               gpio_set_value(OVERO_GPIO_W2W_NRESET, 0);
+               udelay(10);
+               gpio_set_value(OVERO_GPIO_W2W_NRESET, 1);
+       } else {
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_W2W_NRESET\n");
+       }
+
+       if ((gpio_request(OVERO_GPIO_BT_XGATE, "OVERO_GPIO_BT_XGATE") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_BT_XGATE, 0) == 0))
+               gpio_export(OVERO_GPIO_BT_XGATE, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for OVERO_GPIO_BT_XGATE\n");
+
+       if ((gpio_request(OVERO_GPIO_BT_NRESET, "OVERO_GPIO_BT_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_BT_NRESET, 1) == 0)) {
+               gpio_export(OVERO_GPIO_BT_NRESET, 0);
+               gpio_set_value(OVERO_GPIO_BT_NRESET, 0);
+               mdelay(6);
+               gpio_set_value(OVERO_GPIO_BT_NRESET, 1);
+       } else {
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_BT_NRESET\n");
+       }
+
+       if ((gpio_request(OVERO_GPIO_USBH_CPEN, "OVERO_GPIO_USBH_CPEN") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_USBH_CPEN, 1) == 0))
+               gpio_export(OVERO_GPIO_USBH_CPEN, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_USBH_CPEN\n");
+
+       if ((gpio_request(OVERO_GPIO_USBH_NRESET,
+                         "OVERO_GPIO_USBH_NRESET") == 0) &&
+           (gpio_direction_output(OVERO_GPIO_USBH_NRESET, 1) == 0))
+               gpio_export(OVERO_GPIO_USBH_NRESET, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for "
+                                       "OVERO_GPIO_USBH_NRESET\n");
+}
+
+static void __init overo_map_io(void)
+{
+       omap2_set_globals_343x();
+       omap2_map_common_io();
+}
+
+MACHINE_START(OVERO, "Gumstix Overo")
+       .phys_io        = 0x48000000,
+       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
+       .boot_params    = 0x80000100,
+       .map_io         = overo_map_io,
+       .init_irq       = overo_init_irq,
+       .init_machine   = overo_init,
+       .timer          = &omap_timer,
+MACHINE_END
index 1d891e4a69337d76aba8a75cb931e58477935161..c3af24e8e3e557029f3cc07a7c8384d3a4befdd2 100644 (file)
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-#include <asm/bitops.h>
-
-#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
 
 #include <mach/clock.h>
+#include <mach/clockdomain.h>
 #include <mach/sram.h>
 #include <mach/cpu.h>
+#include <mach/prcm.h>
+#include <mach/control.h>
 #include <asm/div64.h>
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "sdrc.h"
 #include "clock.h"
 #include "prm.h"
 #define DPLL_ROUNDING_VAL              ((DPLL_SCALE_BASE / 2) * \
                                         (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
 
+/* Some OMAP2xxx CM_CLKSEL_PLL.ST_CORE_CLK bits - for omap2_get_dpll_rate() */
+#define ST_CORE_CLK_REF                        0x1
+#define ST_CORE_CLK_32K                        0x3
+
+/* Bitmask to isolate the register type of clk.enable_reg */
+#define PRCM_REGTYPE_MASK              0xf0
+/* various CM register type options */
+#define CM_FCLKEN_REGTYPE              0x00
+#define CM_ICLKEN_REGTYPE              0x10
+#define CM_IDLEST_REGTYPE              0x20
+
 u8 cpu_mask;
 
 /*-------------------------------------------------------------------------
- * Omap2 specific clock functions
+ * OMAP2/3 specific clock functions
  *-------------------------------------------------------------------------*/
 
+/*
+ * _omap2_clk_read_reg - read a clock register
+ * @clk: struct clk *
+ *
+ * Given a struct clk *, returns the value of the clock's register.
+ */
+static u32 _omap2_clk_read_reg(u16 reg_offset, struct clk *clk)
+{
+       if (clk->prcm_mod & CLK_REG_IN_SCM)
+               return omap_ctrl_readl(reg_offset);
+       else if (clk->prcm_mod & CLK_REG_IN_PRM)
+               return prm_read_mod_reg(clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+                                       reg_offset);
+       else
+               return cm_read_mod_reg(clk->prcm_mod, reg_offset);
+}
+
+/*
+ * _omap2_clk_write_reg - write a clock's register
+ * @v: value to write to the clock's enable_reg
+ * @clk: struct clk *
+ *
+ * Given a register value @v and struct clk * @clk, writes the value of @v to
+ * the clock's enable register.  No return value.
+ */
+static void _omap2_clk_write_reg(u32 v, u16 reg_offset, struct clk *clk)
+{
+       if (clk->prcm_mod & CLK_REG_IN_SCM)
+               omap_ctrl_writel(v, reg_offset);
+       else if (clk->prcm_mod & CLK_REG_IN_PRM)
+               prm_write_mod_reg(v, clk->prcm_mod & PRCM_MOD_ADDR_MASK,
+                                 reg_offset);
+       else
+               cm_write_mod_reg(v, clk->prcm_mod, reg_offset);
+}
+
+
+/**
+ * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
+ * @clk: OMAP clock struct ptr to use
+ *
+ * Convert a clockdomain name stored in a struct clk 'clk' into a
+ * clockdomain pointer, and save it into the struct clk.  Intended to be
+ * called during clk_register().  No return value.
+ */
+void omap2_init_clk_clkdm(struct clk *clk)
+{
+       struct clockdomain *clkdm;
+
+       if (!clk->clkdm.name) {
+               pr_err("clock: %s: missing clockdomain", clk->name);
+               return;
+       }
+
+       clkdm = clkdm_lookup(clk->clkdm.name);
+       if (clkdm) {
+               pr_debug("clock: associated clk %s to clkdm %s\n",
+                        clk->name, clk->clkdm.name);
+               clk->clkdm.ptr = clkdm;
+       } else {
+               pr_err("clock: %s: could not associate to clkdm %s\n",
+                      clk->name, clk->clkdm.name);
+       }
+}
+
 /**
  * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
  * @clk: OMAP clock struct ptr to use
@@ -82,7 +160,8 @@ void omap2_init_clksel_parent(struct clk *clk)
        if (!clk->clksel)
                return;
 
-       r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+       r = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       r &= clk->clksel_mask;
        r >>= __ffs(clk->clksel_mask);
 
        for (clks = clk->clksel; clks->parent && !found; clks++) {
@@ -108,22 +187,52 @@ void omap2_init_clksel_parent(struct clk *clk)
        return;
 }
 
-/* Returns the DPLL rate */
+/**
+ * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
+ * @clk: struct clk * of a DPLL
+ *
+ * DPLLs can be locked or bypassed - basically, enabled or disabled.
+ * When locked, the DPLL output depends on the M and N values.  When
+ * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
+ * or sys_clk.  Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
+ * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
+ * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
+ * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
+ * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
+ * if the clock @clk is not a DPLL.
+ */
 u32 omap2_get_dpll_rate(struct clk *clk)
 {
        long long dpll_clk;
-       u32 dpll_mult, dpll_div, dpll;
+       u32 dpll_mult, dpll_div, v;
        struct dpll_data *dd;
 
        dd = clk->dpll_data;
-       /* REVISIT: What do we return on error? */
        if (!dd)
                return 0;
 
-       dpll = __raw_readl(dd->mult_div1_reg);
-       dpll_mult = dpll & dd->mult_mask;
+       /* Return bypass rate if DPLL is bypassed */
+       v = cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg);
+       v &= dd->idlest_mask;
+       v >>= __ffs(dd->idlest_mask);
+       if (cpu_is_omap24xx()) {
+
+               if (v == ST_CORE_CLK_REF)
+                       return clk->parent->rate; /* sys_clk */
+               else if (v == ST_CORE_CLK_32K)
+                       return 32768;
+
+       } else if (cpu_is_omap34xx()) {
+
+               if (!v)
+                       return dd->bypass_clk->rate;
+
+       }
+
+       v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
+       dpll_mult = v & dd->mult_mask;
        dpll_mult >>= __ffs(dd->mult_mask);
-       dpll_div = dpll & dd->div1_mask;
+       dpll_div = v & dd->div1_mask;
        dpll_div >>= __ffs(dd->div1_mask);
 
        dpll_clk = (long long)clk->parent->rate * dpll_mult;
@@ -148,30 +257,30 @@ void omap2_fixed_divisor_recalc(struct clk *clk)
 
 /**
  * omap2_wait_clock_ready - wait for clock to enable
- * @reg: physical address of clock IDLEST register
+ * @prcm_mod: CM submodule offset from CM_BASE (e.g., "MPU_MOD")
+ * @reg_index: offset of CM register address from prcm_mod
  * @mask: value to mask against to determine if the clock is active
  * @name: name of the clock (for printk)
  *
  * Returns 1 if the clock enabled in time, or 0 if it failed to enable
  * in roughly MAX_CLOCK_ENABLE_WAIT microseconds.
  */
-int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
+int omap2_wait_clock_ready(s16 prcm_mod, u16 reg_index, u32 mask,
+                          const char *name)
 {
-       int i = 0;
-       int ena = 0;
+       int i = 0, ena = 0;
 
        /*
         * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
         * 34xx reverses this, just to keep us on our toes
         */
-       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) {
+       if (cpu_mask & (RATE_IN_242X | RATE_IN_243X))
                ena = mask;
-       } else if (cpu_mask & RATE_IN_343X) {
+       else if (cpu_mask & RATE_IN_343X)
                ena = 0;
-       }
 
        /* Wait for lock */
-       while (((__raw_readl(reg) & mask) != ena) &&
+       while (((cm_read_mod_reg(prcm_mod, reg_index) & mask) != ena) &&
               (i++ < MAX_CLOCK_ENABLE_WAIT)) {
                udelay(1);
        }
@@ -182,68 +291,64 @@ int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
                printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
                       name, MAX_CLOCK_ENABLE_WAIT);
 
-
        return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
 };
 
 
 /*
- * Note: We don't need special code here for INVERT_ENABLE
- * for the time being since INVERT_ENABLE only applies to clocks enabled by
- * CM_CLKEN_PLL
+ * omap2_clk_wait_ready - wait for a OMAP module to come out of target idle
+ * @clk: struct clk * recently enabled to indicate the module to test
+ *
+ * Wait for an OMAP module with a target idle state bit to come out of
+ * idle once both its interface clock and primary functional clock are
+ * both enabled.  Any register read or write to the device before it
+ * returns from idle will cause an abort.  Not all modules have target
+ * idle state bits (for example, DSS and CAM on OMAP24xx); so we don't
+ * wait for those.  No return value.
+ *
+ * We don't need special code here for INVERT_ENABLE for the time
+ * being since INVERT_ENABLE only applies to clocks enabled by
+ * CM_CLKEN_PLL.
+ *
+ * REVISIT: This function is misnamed: it should be something like
+ * "omap2_module_wait_ready", and in the long-term, it does not belong
+ * in the clock framework. It also shouldn't be doing register
+ * arithmetic to determine the companion clock.
  */
 static void omap2_clk_wait_ready(struct clk *clk)
 {
-       void __iomem *reg, *other_reg, *st_reg;
-       u32 bit;
+       u16 other_reg, idlest_reg;
+       u32 other_bit;
 
-       /*
-        * REVISIT: This code is pretty ugly.  It would be nice to generalize
-        * it and pull it into struct clk itself somehow.
-        */
-       reg = clk->enable_reg;
-       if ((((u32)reg & 0xff) >= CM_FCLKEN1) &&
-           (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */
-       else if ((((u32)reg & 0xff) >= CM_ICLKEN1) &&
-                (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4))
-               other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */
-       else
+       if (!(clk->flags & WAIT_READY))
                return;
 
-       /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* No check for DSS or cam clocks */
-       if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */
-               if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT ||
-                   clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT ||
-                   clk->enable_bit == OMAP24XX_EN_CAM_SHIFT)
-                       return;
-       }
+       /* If we are enabling an iclk, also test the fclk; and vice versa */
+       other_bit = 1 << clk->enable_bit;
+       other_reg = clk->enable_reg & ~PRCM_REGTYPE_MASK;
 
-       /* REVISIT: What are the appropriate exclusions for 34XX? */
-       /* OMAP3: ignore DSS-mod clocks */
-       if (cpu_is_omap34xx() &&
-           (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0) ||
-            ((((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(CORE_MOD, 0)) &&
-            clk->enable_bit == OMAP3430_EN_SSI_SHIFT)))
-               return;
+       if (clk->enable_reg & CM_ICLKEN_REGTYPE)
+               other_reg |= CM_FCLKEN_REGTYPE;
+       else
+               other_reg |= CM_ICLKEN_REGTYPE;
 
-       /* Check if both functional and interface clocks
-        * are running. */
-       bit = 1 << clk->enable_bit;
-       if (!(__raw_readl(other_reg) & bit))
+       /* Ensure functional and interface clocks are running. */
+       if (!(cm_read_mod_reg(clk->prcm_mod, other_reg) & other_bit))
                return;
-       st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */
 
-       omap2_wait_clock_ready(st_reg, bit, clk->name);
+       idlest_reg = other_reg & ~PRCM_REGTYPE_MASK;
+       idlest_reg |= CM_IDLEST_REGTYPE;
+
+       omap2_wait_clock_ready(clk->prcm_mod, idlest_reg, 1 << clk->idlest_bit,
+                              clk->name);
 }
 
 /* Enables clock without considering parent dependencies or use count
  * REVISIT: Maybe change this to use clk->enable like on omap1?
  */
-int _omap2_clk_enable(struct clk *clk)
+static int _omap2_clk_enable(struct clk *clk)
 {
-       u32 regval32;
+       u32 v;
 
        if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
                return 0;
@@ -251,18 +356,12 @@ int _omap2_clk_enable(struct clk *clk)
        if (clk->enable)
                return clk->enable(clk);
 
-       if (unlikely(clk->enable_reg == 0)) {
-               printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
-                      clk->name);
-               return 0; /* REVISIT: -EINVAL */
-       }
-
-       regval32 = __raw_readl(clk->enable_reg);
+       v = _omap2_clk_read_reg(clk->enable_reg, clk);
        if (clk->flags & INVERT_ENABLE)
-               regval32 &= ~(1 << clk->enable_bit);
+               v &= ~(1 << clk->enable_bit);
        else
-               regval32 |= (1 << clk->enable_bit);
-       __raw_writel(regval32, clk->enable_reg);
+               v |= (1 << clk->enable_bit);
+       _omap2_clk_write_reg(v, clk->enable_reg, clk);
        wmb();
 
        omap2_clk_wait_ready(clk);
@@ -271,9 +370,9 @@ int _omap2_clk_enable(struct clk *clk)
 }
 
 /* Disables clock without considering parent dependencies or use count */
-void _omap2_clk_disable(struct clk *clk)
+static void _omap2_clk_disable(struct clk *clk)
 {
-       u32 regval32;
+       u32 v;
 
        if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK))
                return;
@@ -283,22 +382,12 @@ void _omap2_clk_disable(struct clk *clk)
                return;
        }
 
-       if (clk->enable_reg == 0) {
-               /*
-                * 'Independent' here refers to a clock which is not
-                * controlled by its parent.
-                */
-               printk(KERN_ERR "clock: clk_disable called on independent "
-                      "clock %s which has no enable_reg\n", clk->name);
-               return;
-       }
-
-       regval32 = __raw_readl(clk->enable_reg);
+       v = _omap2_clk_read_reg(clk->enable_reg, clk);
        if (clk->flags & INVERT_ENABLE)
-               regval32 |= (1 << clk->enable_bit);
+               v |= (1 << clk->enable_bit);
        else
-               regval32 &= ~(1 << clk->enable_bit);
-       __raw_writel(regval32, clk->enable_reg);
+               v &= ~(1 << clk->enable_bit);
+       _omap2_clk_write_reg(v, clk->enable_reg, clk);
        wmb();
 }
 
@@ -306,8 +395,11 @@ void omap2_clk_disable(struct clk *clk)
 {
        if (clk->usecount > 0 && !(--clk->usecount)) {
                _omap2_clk_disable(clk);
-               if (likely((u32)clk->parent))
+               if (clk->parent)
                        omap2_clk_disable(clk->parent);
+               if (clk->clkdm.ptr)
+                       omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+
        }
 }
 
@@ -316,19 +408,27 @@ int omap2_clk_enable(struct clk *clk)
        int ret = 0;
 
        if (clk->usecount++ == 0) {
-               if (likely((u32)clk->parent))
+               if (clk->parent)
                        ret = omap2_clk_enable(clk->parent);
 
-               if (unlikely(ret != 0)) {
+               if (ret != 0) {
                        clk->usecount--;
                        return ret;
                }
 
+               if (clk->clkdm.ptr)
+                       omap2_clkdm_clk_enable(clk->clkdm.ptr, clk);
+
                ret = _omap2_clk_enable(clk);
 
-               if (unlikely(ret != 0) && clk->parent) {
-                       omap2_clk_disable(clk->parent);
-                       clk->usecount--;
+               if (ret != 0) {
+                       if (clk->clkdm.ptr)
+                               omap2_clkdm_clk_disable(clk->clkdm.ptr, clk);
+
+                       if (clk->parent) {
+                               omap2_clk_disable(clk->parent);
+                               clk->usecount--;
+                       }
                }
        }
 
@@ -349,13 +449,13 @@ void omap2_clksel_recalc(struct clk *clk)
        if (div == 0)
                return;
 
-       if (unlikely(clk->rate == clk->parent->rate / div))
+       if (clk->rate == (clk->parent->rate / div))
                return;
        clk->rate = clk->parent->rate / div;
 
        pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div);
 
-       if (unlikely(clk->flags & RATE_PROPAGATES))
+       if (clk->flags & RATE_PROPAGATES)
                propagate_rate(clk);
 }
 
@@ -368,8 +468,8 @@ void omap2_clksel_recalc(struct clk *clk)
  * the element associated with the supplied parent clock address.
  * Returns a pointer to the struct clksel on success or NULL on error.
  */
-const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
-                                               struct clk *src_clk)
+static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
+                                                      struct clk *src_clk)
 {
        const struct clksel *clks;
 
@@ -418,7 +518,7 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
        *new_div = 1;
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return ~0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -477,7 +577,7 @@ long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
 /* Given a clock and a rate apply a clock specific rounding function */
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       if (clk->round_rate != 0)
+       if (clk->round_rate != NULL)
                return clk->round_rate(clk, rate);
 
        if (clk->flags & RATE_FIXED)
@@ -503,7 +603,7 @@ u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
        const struct clksel_rate *clkr;
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -539,7 +639,7 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
        WARN_ON(div == 0);
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -557,23 +657,6 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
        return clkr->val;
 }
 
-/**
- * omap2_get_clksel - find clksel register addr & field mask for a clk
- * @clk: struct clk to use
- * @field_mask: ptr to u32 to store the register field mask
- *
- * Returns the address of the clksel register upon success or NULL on error.
- */
-void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
-{
-       if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0)))
-               return NULL;
-
-       *field_mask = clk->clksel_mask;
-
-       return clk->clksel_reg;
-}
-
 /**
  * omap2_clksel_get_divisor - get current divider applied to parent clock.
  * @clk: OMAP struct clk to use.
@@ -582,40 +665,38 @@ void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask)
  */
 u32 omap2_clksel_get_divisor(struct clk *clk)
 {
-       u32 field_mask, field_val;
-       void __iomem *div_addr;
+       u32 v;
 
-       div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
+       if (!clk->clksel_mask)
                return 0;
 
-       field_val = __raw_readl(div_addr) & field_mask;
-       field_val >>= __ffs(field_mask);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= clk->clksel_mask;
+       v >>= __ffs(clk->clksel_mask);
 
-       return omap2_clksel_to_divisor(clk, field_val);
+       return omap2_clksel_to_divisor(clk, v);
 }
 
 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 field_mask, field_val, reg_val, validrate, new_div = 0;
-       void __iomem *div_addr;
+       u32 v, field_val, validrate, new_div = 0;
 
-       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
-       if (validrate != rate)
+       if (!clk->clksel_mask)
                return -EINVAL;
 
-       div_addr = omap2_get_clksel(clk, &field_mask);
-       if (div_addr == 0)
-               return -EINVAL;
+       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+       if (validrate != rate)
+              return -EINVAL;
 
        field_val = omap2_divisor_to_clksel(clk, new_div);
        if (field_val == ~0)
                return -EINVAL;
 
-       reg_val = __raw_readl(div_addr);
-       reg_val &= ~field_mask;
-       reg_val |= (field_val << __ffs(field_mask));
-       __raw_writel(reg_val, div_addr);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       _omap2_clk_write_reg(v, clk->clksel_reg, clk);
+
        wmb();
 
        clk->rate = clk->parent->rate / new_div;
@@ -643,10 +724,10 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
                return -EINVAL;
 
        /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
-       if (clk->set_rate != 0)
+       if (clk->set_rate != NULL)
                ret = clk->set_rate(clk, rate);
 
-       if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+       if (ret == 0 && (clk->flags & RATE_PROPAGATES))
                propagate_rate(clk);
 
        return ret;
@@ -654,20 +735,16 @@ int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
 
 /*
  * Converts encoded control register address into a full address
- * On error, *src_addr will be returned as 0.
+ * On error, the return value (parent_div) will be 0.
  */
-static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
-                                     struct clk *src_clk, u32 *field_mask,
-                                     struct clk *clk, u32 *parent_div)
+static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
+                                      u32 *field_val)
 {
        const struct clksel *clks;
        const struct clksel_rate *clkr;
 
-       *parent_div = 0;
-       *src_addr = 0;
-
        clks = omap2_get_clksel_by_parent(clk, src_clk);
-       if (clks == NULL)
+       if (!clks)
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
@@ -685,40 +762,38 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
        /* Should never happen.  Add a clksel mask to the struct clk. */
        WARN_ON(clk->clksel_mask == 0);
 
-       *field_mask = clk->clksel_mask;
-       *src_addr = clk->clksel_reg;
-       *parent_div = clkr->div;
+       *field_val = clkr->val;
 
-       return clkr->val;
+       return clkr->div;
 }
 
 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 {
-       void __iomem *src_addr;
-       u32 field_val, field_mask, reg_val, parent_div;
+       u32 field_val, v, parent_div;
 
-       if (unlikely(clk->flags & CONFIG_PARTICIPANT))
+       if (clk->flags & CONFIG_PARTICIPANT)
                return -EINVAL;
 
        if (!clk->clksel)
                return -EINVAL;
 
-       field_val = omap2_clksel_get_src_field(&src_addr, new_parent,
-                                              &field_mask, clk, &parent_div);
-       if (src_addr == 0)
+       parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
+       if (!parent_div)
                return -EINVAL;
 
        if (clk->usecount > 0)
                _omap2_clk_disable(clk);
 
        /* Set new source value (previous dividers if any in effect) */
-       reg_val = __raw_readl(src_addr) & ~field_mask;
-       reg_val |= (field_val << __ffs(field_mask));
-       __raw_writel(reg_val, src_addr);
+       v = _omap2_clk_read_reg(clk->clksel_reg, clk);
+       v &= ~clk->clksel_mask;
+       v |= field_val << __ffs(clk->clksel_mask);
+       _omap2_clk_write_reg(v, clk->clksel_reg, clk);
        wmb();
 
        if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) {
-               __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL);
+               prm_write_mod_reg(OMAP24XX_VALID_CONFIG,
+                       OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET);
                wmb();
        }
 
@@ -736,7 +811,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
        pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
                 clk->name, clk->parent->name, clk->rate);
 
-       if (unlikely(clk->flags & RATE_PROPAGATES))
+       if (clk->flags & RATE_PROPAGATES)
                propagate_rate(clk);
 
        return 0;
@@ -768,7 +843,8 @@ int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance)
        return 0;
 }
 
-static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, unsigned int m, unsigned int n)
+static unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
+                                           unsigned int m, unsigned int n)
 {
        unsigned long long num;
 
@@ -931,7 +1007,7 @@ void omap2_clk_disable_unused(struct clk *clk)
 
        v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
 
-       regval32 = __raw_readl(clk->enable_reg);
+       regval32 = _omap2_clk_read_reg(clk->enable_reg, clk);
        if ((regval32 & (1 << clk->enable_bit)) == v)
                return;
 
index 626e5fa93b6ad3a9fd6e79164d9092dc29c4935d..bcb0c0362d027fa693bf9f1f8723b3e7ffe51349 100644 (file)
 /* The maximum error between a target DPLL rate and the rounded rate in Hz */
 #define DEFAULT_DPLL_RATE_TOLERANCE    50000
 
+int omap2_clk_init(void);
 int omap2_clk_enable(struct clk *clk);
 void omap2_clk_disable(struct clk *clk);
 long omap2_clk_round_rate(struct clk *clk, unsigned long rate);
 int omap2_clk_set_rate(struct clk *clk, unsigned long rate);
 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent);
-int omap2_dpll_rate_tolerance_set(struct clk *clk, unsigned int tolerance);
+int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
 long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
 
 #ifdef CONFIG_OMAP_RESET_CLOCKS
@@ -36,6 +37,7 @@ void omap2_clk_disable_unused(struct clk *clk);
 #endif
 
 void omap2_clksel_recalc(struct clk *clk);
+void omap2_init_clk_clkdm(struct clk *clk);
 void omap2_init_clksel_parent(struct clk *clk);
 u32 omap2_clksel_get_divisor(struct clk *clk);
 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
@@ -46,7 +48,8 @@ void omap2_fixed_divisor_recalc(struct clk *clk);
 long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
 u32 omap2_get_dpll_rate(struct clk *clk);
-int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name);
+int omap2_wait_clock_ready(s16 prcm_mod, u16 idlest_reg, u32 cval,
+                          const char *name);
 void omap2_clk_prepare_for_reboot(void);
 
 extern u8 cpu_mask;
index 295e671e9cfdbcb397560cac97d881960077c07c..a54f10f92cd436bbd504301976d288abacb978b6 100644 (file)
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-
+#include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/cpufreq.h>
 
+#include <mach/common.h>
 #include <mach/clock.h>
 #include <mach/sram.h>
 #include <asm/div64.h>
-#include <asm/bitops.h>
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "clock.h"
 #include "clock24xx.h"
 #include "prm.h"
@@ -77,37 +77,17 @@ static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
 
 static int omap2_enable_osc_ck(struct clk *clk)
 {
-       u32 pcc;
-
-       pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
-
-       __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
-                     OMAP24XX_PRCM_CLKSRC_CTRL);
+       prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, 0,
+                       OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
 
        return 0;
 }
 
 static void omap2_disable_osc_ck(struct clk *clk)
 {
-       u32 pcc;
-
-       pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
-
-       __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
-                     OMAP24XX_PRCM_CLKSRC_CTRL);
-}
-
-#ifdef OLD_CK
-/* Recalculate SYST_CLK */
-static void omap2_sys_clk_recalc(struct clk * clk)
-{
-       u32 div = PRCM_CLKSRC_CTRL;
-       div &= (1 << 7) | (1 << 6);     /* Test if ext clk divided by 1 or 2 */
-       div >>= clk->rate_offset;
-       clk->rate = (clk->parent->rate / div);
-       propagate_rate(clk);
+       prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, OMAP_AUTOEXTCLKMODE_MASK,
+                       OMAP24XX_GR_MOD, OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
 }
-#endif /* OLD_CK */
 
 /* Enable an APLL if off */
 static int omap2_clk_fixed_enable(struct clk *clk)
@@ -130,8 +110,7 @@ static int omap2_clk_fixed_enable(struct clk *clk)
        else if (clk == &apll54_ck)
                cval = OMAP24XX_ST_54M_APLL;
 
-       omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
-                           clk->name);
+       omap2_wait_clock_ready(PLL_MOD, CM_IDLEST, cval, clk->name);
 
        /*
         * REVISIT: Should we return an error code if omap2_wait_clock_ready()
@@ -154,7 +133,7 @@ static void omap2_clk_fixed_disable(struct clk *clk)
  * Uses the current prcm set to tell if a rate is valid.
  * You can go slower, but not faster within a given rate set.
  */
-long omap2_dpllcore_round_rate(unsigned long target_rate)
+static long omap2_dpllcore_round_rate(unsigned long target_rate)
 {
        u32 high, low, core_clk_src;
 
@@ -205,9 +184,9 @@ static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
        mult &= OMAP24XX_CORE_CLK_SRC_MASK;
 
        if ((rate == (cur_rate / 2)) && (mult == 2)) {
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
        } else if ((rate == (cur_rate * 2)) && (mult == 1)) {
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
        } else if (rate != cur_rate) {
                valid_rate = omap2_dpllcore_round_rate(rate);
                if (valid_rate != rate)
@@ -222,7 +201,8 @@ static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
                if (!dd)
                        goto dpll_exit;
 
-               tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
+               tmpset.cm_clksel1_pll = cm_read_mod_reg(clk->prcm_mod,
+                                                       dd->mult_div1_reg);
                tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
                                           dd->div1_mask);
                div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
@@ -246,15 +226,16 @@ static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
                if (rate == curr_prcm_set->xtal_speed)  /* If asking for 1-1 */
                        bypass = 1;
 
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */
+               /* For omap2xxx_sdrc_init_params() */
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
 
                /* Force dll lock mode */
                omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
                               bypass);
 
                /* Errata: ret dll entry state */
-               omap2_init_memory_params(omap2_dll_force_needed());
-               omap2_reprogram_sdrc(done_rate, 0);
+               omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
+               omap2xxx_sdrc_reprogram(done_rate, 0);
        }
        omap2_dpllcore_recalc(&dpll_ck);
        ret = 0;
@@ -341,9 +322,9 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
        cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
 
        if (prcm->dpll_speed == cur_rate / 2) {
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
        } else if (prcm->dpll_speed == cur_rate * 2) {
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
        } else if (prcm->dpll_speed != cur_rate) {
                local_irq_save(flags);
 
@@ -367,19 +348,21 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
 
                /* Major subsystem dividers */
                tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK;
-               cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1);
+               cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD,
+                                CM_CLKSEL1);
+
                if (cpu_is_omap2430())
                        cm_write_mod_reg(prcm->cm_clksel_mdm,
                                         OMAP2430_MDM_MOD, CM_CLKSEL);
 
-               /* x2 to enter init_mem */
-               omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
+               /* x2 to enter omap2xxx_sdrc_init_params() */
+               omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
 
                omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
                               bypass);
 
-               omap2_init_memory_params(omap2_dll_force_needed());
-               omap2_reprogram_sdrc(done_rate, 0);
+               omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
+               omap2xxx_sdrc_reprogram(done_rate, 0);
 
                local_irq_restore(flags);
        }
@@ -388,6 +371,45 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
        return 0;
 }
 
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Walk PRCM rate table and fillout cpufreq freq_table
+ */
+static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(rate_table)];
+
+void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+       struct prcm_config *prcm;
+       int i = 0;
+
+       for (prcm = rate_table; prcm->mpu_speed; prcm++) {
+               if (!(prcm->flags & cpu_mask))
+                       continue;
+               if (prcm->xtal_speed != sys_ck.rate)
+                       continue;
+
+               /* don't put bypass rates in table */
+               if (prcm->dpll_speed == prcm->xtal_speed)
+                       continue;
+
+               freq_table[i].index = i;
+               freq_table[i].frequency = prcm->mpu_speed / 1000;
+               i++;
+       }
+
+       if (i == 0) {
+               printk(KERN_WARNING "%s: failed to initialize frequency "
+                      "table\n", __func__);
+               return;
+       }
+
+       freq_table[i].index = i;
+       freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+       *table = &freq_table[0];
+}
+#endif
+
 static struct clk_functions omap2_clk_functions = {
        .clk_enable             = omap2_clk_enable,
        .clk_disable            = omap2_clk_disable,
@@ -395,31 +417,35 @@ static struct clk_functions omap2_clk_functions = {
        .clk_set_rate           = omap2_clk_set_rate,
        .clk_set_parent         = omap2_clk_set_parent,
        .clk_disable_unused     = omap2_clk_disable_unused,
+#ifdef CONFIG_CPU_FREQ
+       .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table,
+#endif
 };
 
 static u32 omap2_get_apll_clkin(void)
 {
-       u32 aplls, sclk = 0;
+       u32 aplls, srate = 0;
 
        aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
        aplls &= OMAP24XX_APLLS_CLKIN_MASK;
        aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
 
        if (aplls == APLLS_CLKIN_19_2MHZ)
-               sclk = 19200000;
+               srate = 19200000;
        else if (aplls == APLLS_CLKIN_13MHZ)
-               sclk = 13000000;
+               srate = 13000000;
        else if (aplls == APLLS_CLKIN_12MHZ)
-               sclk = 12000000;
+               srate = 12000000;
 
-       return sclk;
+       return srate;
 }
 
 static u32 omap2_get_sysclkdiv(void)
 {
        u32 div;
 
-       div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
+       div = prm_read_mod_reg(OMAP24XX_GR_MOD,
+                               OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
        div &= OMAP_SYSCLKDIV_MASK;
        div >>= OMAP_SYSCLKDIV_SHIFT;
 
@@ -497,11 +523,13 @@ int __init omap2_clk_init(void)
 
                if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {
                        clk_register(*clkp);
+                       omap2_init_clk_clkdm(*clkp);
                        continue;
                }
 
                if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {
                        clk_register(*clkp);
+                       omap2_init_clk_clkdm(*clkp);
                        continue;
                }
        }
index be4e25554e05dfe0ad608a837f763164bf3275df..8bf70cfa3230ec4cbb4c4a886e0b3e3792974035 100644 (file)
@@ -626,6 +626,7 @@ static struct clk func_32k_ck = {
        .rate           = 32000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -634,17 +635,19 @@ static struct clk osc_ck = {              /* (*12, *13, 19.2, *26, 38.4)MHz */
        .name           = "osc_ck",
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES,
+       .clkdm          = { .name = "prm_clkdm" },
        .enable         = &omap2_enable_osc_ck,
        .disable        = &omap2_disable_osc_ck,
        .recalc         = &omap2_osc_clk_recalc,
 };
 
-/* With out modem likely 12MHz, with modem likely 13MHz */
+/* Without modem likely 12MHz, with modem likely 13MHz */
 static struct clk sys_ck = {           /* (*12, *13, 19.2, 26, 38.4)MHz */
        .name           = "sys_ck",             /* ~ ref_clk also */
        .parent         = &osc_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_sys_clk_recalc,
 };
 
@@ -653,6 +656,7 @@ static struct clk alt_ck = {                /* Typical 54M or 48M, may not exist */
        .rate           = 54000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -666,9 +670,11 @@ static struct clk alt_ck = {               /* Typical 54M or 48M, may not exist */
  */
 
 static struct dpll_data dpll_dd = {
-       .mult_div1_reg          = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .mult_div1_reg          = CM_CLKSEL1,
        .mult_mask              = OMAP24XX_DPLL_MULT_MASK,
        .div1_mask              = OMAP24XX_DPLL_DIV_MASK,
+       .idlest_reg             = CM_IDLEST,
+       .idlest_mask            = OMAP24XX_ST_CORE_CLK_MASK,
        .max_multiplier         = 1024,
        .max_divider            = 16,
        .rate_tolerance         = DEFAULT_DPLL_RATE_TOLERANCE
@@ -681,9 +687,11 @@ static struct dpll_data dpll_dd = {
 static struct clk dpll_ck = {
        .name           = "dpll_ck",
        .parent         = &sys_ck,              /* Can be func_32k also */
+       .prcm_mod       = PLL_MOD,
        .dpll_data      = &dpll_dd,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_dpllcore_recalc,
        .set_rate       = &omap2_reprogram_dpllcore,
 };
@@ -691,10 +699,12 @@ static struct clk dpll_ck = {
 static struct clk apll96_ck = {
        .name           = "apll96_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .rate           = 96000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP24XX_EN_96M_PLL_SHIFT,
        .enable         = &omap2_clk_fixed_enable,
        .disable        = &omap2_clk_fixed_disable,
@@ -704,10 +714,12 @@ static struct clk apll96_ck = {
 static struct clk apll54_ck = {
        .name           = "apll54_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .rate           = 54000000,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_FIXED | RATE_PROPAGATES | ENABLE_ON_INIT,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP24XX_EN_54M_PLL_SHIFT,
        .enable         = &omap2_clk_fixed_enable,
        .disable        = &omap2_clk_fixed_disable,
@@ -739,10 +751,12 @@ static const struct clksel func_54m_clksel[] = {
 static struct clk func_54m_ck = {
        .name           = "func_54m_ck",
        .parent         = &apll54_ck,   /* can also be alt_clk */
+       .prcm_mod       = PLL_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_54M_SOURCE,
        .clksel         = func_54m_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -753,6 +767,7 @@ static struct clk core_ck = {
        .parent         = &dpll_ck,             /* can also be 32k */
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | RATE_PROPAGATES,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -777,10 +792,12 @@ static const struct clksel func_96m_clksel[] = {
 static struct clk func_96m_ck = {
        .name           = "func_96m_ck",
        .parent         = &apll96_ck,
+       .prcm_mod       = PLL_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP2430_96M_SOURCE,
        .clksel         = func_96m_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -809,10 +826,12 @@ static const struct clksel func_48m_clksel[] = {
 static struct clk func_48m_ck = {
        .name           = "func_48m_ck",
        .parent         = &apll96_ck,    /* 96M or Alt */
+       .prcm_mod       = PLL_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_48M_SOURCE,
        .clksel         = func_48m_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -826,14 +845,16 @@ static struct clk func_12m_ck = {
        .fixed_div      = 4,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_fixed_divisor_recalc,
 };
 
 /* Secure timer, only available in secure mode */
 static struct clk wdt1_osc_ck = {
-       .name           = "ck_wdt1_osc",
+       .name           = "wdt1_osc_ck",
        .parent         = &osc_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -876,12 +897,14 @@ static const struct clksel common_clkout_src_clksel[] = {
 static struct clk sys_clkout_src = {
        .name           = "sys_clkout_src",
        .parent         = &func_54m_ck,
+       .prcm_mod       = OMAP24XX_GR_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                RATE_PROPAGATES,
-       .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .enable_bit     = OMAP24XX_CLKOUT_EN_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP24XX_CLKOUT_SOURCE_MASK,
        .clksel         = common_clkout_src_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -906,9 +929,11 @@ static const struct clksel sys_clkout_clksel[] = {
 static struct clk sys_clkout = {
        .name           = "sys_clkout",
        .parent         = &sys_clkout_src,
+       .prcm_mod       = OMAP24XX_GR_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                PARENT_CONTROLS_CLOCK,
-       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clkdm          = { .name = "prm_clkdm" },
+       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP24XX_CLKOUT_DIV_MASK,
        .clksel         = sys_clkout_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -920,11 +945,13 @@ static struct clk sys_clkout = {
 static struct clk sys_clkout2_src = {
        .name           = "sys_clkout2_src",
        .parent         = &func_54m_ck,
+       .prcm_mod       = OMAP24XX_GR_MOD,
        .flags          = CLOCK_IN_OMAP242X | RATE_PROPAGATES,
-       .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clkdm          = { .name = "cm_clkdm" },
+       .enable_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .enable_bit     = OMAP2420_CLKOUT2_EN_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP2420_CLKOUT2_SOURCE_MASK,
        .clksel         = common_clkout_src_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -941,8 +968,10 @@ static const struct clksel sys_clkout2_clksel[] = {
 static struct clk sys_clkout2 = {
        .name           = "sys_clkout2",
        .parent         = &sys_clkout2_src,
+       .prcm_mod       = OMAP24XX_GR_MOD,
        .flags          = CLOCK_IN_OMAP242X | PARENT_CONTROLS_CLOCK,
-       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL,
+       .clkdm          = { .name = "cm_clkdm" },
+       .clksel_reg     = OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP2420_CLKOUT2_DIV_MASK,
        .clksel         = sys_clkout2_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -953,8 +982,10 @@ static struct clk sys_clkout2 = {
 static struct clk emul_ck = {
        .name           = "emul_ck",
        .parent         = &func_54m_ck,
+       .prcm_mod       = OMAP24XX_GR_MOD,
        .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP24XX_PRCM_CLKEMUL_CTRL,
+       .clkdm          = { .name = "cm_clkdm" },
+       .enable_reg     = OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET,
        .enable_bit     = OMAP24XX_EMULATION_EN_SHIFT,
        .recalc         = &followparent_recalc,
 
@@ -987,15 +1018,17 @@ static const struct clksel mpu_clksel[] = {
 static struct clk mpu_ck = {   /* Control cpu */
        .name           = "mpu_ck",
        .parent         = &core_ck,
+       .prcm_mod       = MPU_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
+       .clkdm          = { .name = "mpu_clkdm" },
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP24XX_CLKSEL_MPU_MASK,
        .clksel         = mpu_clksel,
        .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
+       .round_rate     = &omap2_clksel_round_rate,
        .set_rate       = &omap2_clksel_set_rate
 };
 
@@ -1029,11 +1062,13 @@ static const struct clksel dsp_fck_clksel[] = {
 static struct clk dsp_fck = {
        .name           = "dsp_fck",
        .parent         = &core_ck,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "dsp_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP24XX_CLKSEL_DSP_MASK,
        .clksel         = dsp_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1054,29 +1089,30 @@ static const struct clksel dsp_irate_ick_clksel[] = {
        { .parent = NULL }
 };
 
-/*
- * This clock does not exist as such in the TRM, but is added to
- * separate source selection from  XXX
- */
+/* This clock does not exist as such in the TRM. */
 static struct clk dsp_irate_ick = {
        .name           = "dsp_irate_ick",
        .parent         = &dsp_fck,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | DELAYED_APP |
                                CONFIG_PARTICIPANT | PARENT_CONTROLS_CLOCK,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+       .clkdm          = { .name = "dsp_clkdm" },
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP24XX_CLKSEL_DSP_IF_MASK,
        .clksel         = dsp_irate_ick_clksel,
        .recalc         = &omap2_clksel_recalc,
        .round_rate     = &omap2_clksel_round_rate,
-       .set_rate             = &omap2_clksel_set_rate
+       .set_rate       = &omap2_clksel_set_rate
 };
 
 /* 2420 only */
 static struct clk dsp_ick = {
        .name           = "dsp_ick",     /* apparently ipi and isp */
        .parent         = &dsp_irate_ick,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP242X | DELAYED_APP | CONFIG_PARTICIPANT,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN),
+       .clkdm          = { .name = "dsp_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP2420_EN_DSP_IPI_SHIFT,          /* for ipi */
 };
 
@@ -1084,19 +1120,28 @@ static struct clk dsp_ick = {
 static struct clk iva2_1_ick = {
        .name           = "iva2_1_ick",
        .parent         = &dsp_irate_ick,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP243X | DELAYED_APP | CONFIG_PARTICIPANT,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "dsp_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT,
 };
 
+/*
+ * The IVA1 is an ARM7 core on the 2420 that has nothing to do with
+ * the C54x, but which is contained in the DSP powerdomain.  Does not
+ * exist on later OMAPs.
+ */
 static struct clk iva1_ifck = {
        .name           = "iva1_ifck",
        .parent         = &core_ck,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP242X | CONFIG_PARTICIPANT |
                                RATE_PROPAGATES | DELAYED_APP,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "iva1_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP2420_EN_IVA_COP_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP2420_CLKSEL_IVA_MASK,
        .clksel         = dsp_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1108,8 +1153,10 @@ static struct clk iva1_ifck = {
 static struct clk iva1_mpu_int_ifck = {
        .name           = "iva1_mpu_int_ifck",
        .parent         = &iva1_ifck,
+       .prcm_mod       = OMAP24XX_DSP_MOD,
        .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "iva1_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP2420_EN_IVA_MPU_SHIFT,
        .fixed_div      = 2,
        .recalc         = &omap2_fixed_divisor_recalc,
@@ -1153,10 +1200,12 @@ static const struct clksel core_l3_clksel[] = {
 static struct clk core_l3_ck = {       /* Used for ick and fck, interconnect */
        .name           = "core_l3_ck",
        .parent         = &core_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                ALWAYS_ENABLED | DELAYED_APP |
                                CONFIG_PARTICIPANT | RATE_PROPAGATES,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_L3_MASK,
        .clksel         = core_l3_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1177,14 +1226,18 @@ static const struct clksel usb_l4_ick_clksel[] = {
        { .parent = NULL },
 };
 
+/* It is unclear from TRM whether usb_l4_ick is really in L3 or L4 clkdm */
 static struct clk usb_l4_ick = {       /* FS-USB interface clock */
        .name           = "usb_l4_ick",
        .parent         = &core_l3_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-                               DELAYED_APP | CONFIG_PARTICIPANT,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+                               DELAYED_APP | CONFIG_PARTICIPANT | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP24XX_EN_USB_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .idlest_bit     = OMAP24XX_ST_USB_SHIFT,
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_USB_MASK,
        .clksel         = usb_l4_ick_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1192,11 +1245,44 @@ static struct clk usb_l4_ick = {        /* FS-USB interface clock */
        .set_rate       = &omap2_clksel_set_rate
 };
 
+/*
+ * L4 clock management domain
+ *
+ * This domain contains lots of interface clocks from the L4 interface, some
+ * functional clocks.  Fixed APLL functional source clocks are managed in
+ * this domain.
+ */
+static const struct clksel_rate l4_core_l3_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_24XX | DEFAULT_RATE },
+       { .div = 2, .val = 2, .flags = RATE_IN_24XX },
+       { .div = 0 }
+};
+
+static const struct clksel l4_clksel[] = {
+       { .parent = &core_l3_ck, .rates = l4_core_l3_rates },
+       { .parent = NULL }
+};
+
+static struct clk l4_ck = {            /* used both as an ick and fck */
+       .name           = "l4_ck",
+       .parent         = &core_l3_ck,
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ALWAYS_ENABLED | DELAYED_APP | RATE_PROPAGATES,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .clksel_reg     = CM_CLKSEL1,
+       .clksel_mask    = OMAP24XX_CLKSEL_L4_MASK,
+       .clksel         = l4_clksel,
+       .recalc         = &omap2_clksel_recalc,
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap2_clksel_set_rate
+};
+
 /*
  * SSI is in L3 management domain, its direct parent is core not l3,
  * many core power domain entities are grouped into the L3 clock
  * domain.
- * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_CLIK
+ * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_ICLK
  *
  * ssr = core/1/2/3/4/5, sst = 1/2 ssr.
  */
@@ -1219,11 +1305,14 @@ static const struct clksel ssi_ssr_sst_fck_clksel[] = {
 static struct clk ssi_ssr_sst_fck = {
        .name           = "ssi_fck",
        .parent         = &core_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY |
                                DELAYED_APP,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP24XX_EN_SSI_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .idlest_bit     = OMAP24XX_ST_SSI_SHIFT,
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_SSI_MASK,
        .clksel         = ssi_ssr_sst_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1231,6 +1320,23 @@ static struct clk ssi_ssr_sst_fck = {
        .set_rate       = &omap2_clksel_set_rate
 };
 
+/*
+ * Presumably this is the same as SSI_ICLK.
+ * TRM contradicts itself on what clockdomain SSI_ICLK is in
+ */
+static struct clk ssi_l4_ick = {
+       .name           = "ssi_l4_ick",
+       .parent         = &l4_ck,
+       .prcm_mod       = CORE_MOD,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .enable_reg     = CM_ICLKEN2,
+       .enable_bit     = OMAP24XX_EN_SSI_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_SSI_SHIFT,
+       .recalc         = &followparent_recalc,
+};
+
+
 /*
  * GFX clock domain
  *     Clocks:
@@ -1253,10 +1359,12 @@ static const struct clksel gfx_fck_clksel[] = {
 static struct clk gfx_3d_fck = {
        .name           = "gfx_3d_fck",
        .parent         = &core_l3_ck,
+       .prcm_mod       = GFX_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "gfx_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_EN_3D_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP_CLKSEL_GFX_MASK,
        .clksel         = gfx_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1267,10 +1375,12 @@ static struct clk gfx_3d_fck = {
 static struct clk gfx_2d_fck = {
        .name           = "gfx_2d_fck",
        .parent         = &core_l3_ck,
+       .prcm_mod       = GFX_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "gfx_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_EN_2D_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP_CLKSEL_GFX_MASK,
        .clksel         = gfx_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1281,8 +1391,10 @@ static struct clk gfx_2d_fck = {
 static struct clk gfx_ick = {
        .name           = "gfx_ick",            /* From l3 */
        .parent         = &core_l3_ck,
+       .prcm_mod       = GFX_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
+       .clkdm          = { .name = "gfx_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP_EN_GFX_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1310,10 +1422,12 @@ static const struct clksel mdm_ick_clksel[] = {
 static struct clk mdm_ick = {          /* used both as a ick and fck */
        .name           = "mdm_ick",
        .parent         = &core_ck,
+       .prcm_mod       = OMAP2430_MDM_MOD,
        .flags          = CLOCK_IN_OMAP243X | DELAYED_APP | CONFIG_PARTICIPANT,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_ICLKEN),
+       .clkdm          = { .name = "mdm_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP2430_CM_ICLKEN_MDM_EN_MDM_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP2430_CLKSEL_MDM_MASK,
        .clksel         = mdm_ick_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1324,52 +1438,14 @@ static struct clk mdm_ick = {           /* used both as a ick and fck */
 static struct clk mdm_osc_ck = {
        .name           = "mdm_osc_ck",
        .parent         = &osc_ck,
+       .prcm_mod       = OMAP2430_MDM_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP2430_MDM_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "mdm_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP2430_EN_OSC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
-/*
- * L4 clock management domain
- *
- * This domain contains lots of interface clocks from the L4 interface, some
- * functional clocks.  Fixed APLL functional source clocks are managed in
- * this domain.
- */
-static const struct clksel_rate l4_core_l3_rates[] = {
-       { .div = 1, .val = 1, .flags = RATE_IN_24XX | DEFAULT_RATE },
-       { .div = 2, .val = 2, .flags = RATE_IN_24XX },
-       { .div = 0 }
-};
-
-static const struct clksel l4_clksel[] = {
-       { .parent = &core_l3_ck, .rates = l4_core_l3_rates },
-       { .parent = NULL }
-};
-
-static struct clk l4_ck = {            /* used both as an ick and fck */
-       .name           = "l4_ck",
-       .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
-                               ALWAYS_ENABLED | DELAYED_APP | RATE_PROPAGATES,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
-       .clksel_mask    = OMAP24XX_CLKSEL_L4_MASK,
-       .clksel         = l4_clksel,
-       .recalc         = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-       .set_rate       = &omap2_clksel_set_rate
-};
-
-static struct clk ssi_l4_ick = {
-       .name           = "ssi_l4_ick",
-       .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
-       .enable_bit     = OMAP24XX_EN_SSI_SHIFT,
-       .recalc         = &followparent_recalc,
-};
-
 /*
  * DSS clock domain
  * CLOCKs:
@@ -1408,8 +1484,10 @@ static const struct clksel dss1_fck_clksel[] = {
 static struct clk dss_ick = {          /* Enables both L3,L4 ICLK's */
        .name           = "dss_ick",
        .parent         = &l4_ck,       /* really both l3 and l4 */
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .clkdm          = { .name = "dss_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_DSS1_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1417,12 +1495,14 @@ static struct clk dss_ick = {           /* Enables both L3,L4 ICLK's */
 static struct clk dss1_fck = {
        .name           = "dss1_fck",
        .parent         = &core_ck,             /* Core or sys */
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "dss_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_DSS1_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_DSS1_MASK,
        .clksel         = dss1_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1449,12 +1529,14 @@ static const struct clksel dss2_fck_clksel[] = {
 static struct clk dss2_fck = {         /* Alt clk used in power management */
        .name           = "dss2_fck",
        .parent         = &sys_ck,              /* fixed at sys_ck or 48MHz */
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                DELAYED_APP,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "dss_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_DSS2_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_DSS2_MASK,
        .clksel         = dss2_fck_clksel,
        .recalc         = &followparent_recalc,
@@ -1463,8 +1545,10 @@ static struct clk dss2_fck = {           /* Alt clk used in power management */
 static struct clk dss_54m_fck = {      /* Alt clk used in power management */
        .name           = "dss_54m_fck",        /* 54m tv clk */
        .parent         = &func_54m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "dss_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_TV_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1490,20 +1574,25 @@ static const struct clksel omap24xx_gpt_clksel[] = {
 static struct clk gpt1_ick = {
        .name           = "gpt1_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_GPT1_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt1_fck = {
        .name           = "gpt1_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = WKUP_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_EN_GPT1_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT1_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1514,20 +1603,25 @@ static struct clk gpt1_fck = {
 static struct clk gpt2_ick = {
        .name           = "gpt2_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT2_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt2_fck = {
        .name           = "gpt2_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT2_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT2_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1536,20 +1630,25 @@ static struct clk gpt2_fck = {
 static struct clk gpt3_ick = {
        .name           = "gpt3_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT3_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt3_fck = {
        .name           = "gpt3_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT3_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT3_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1558,20 +1657,25 @@ static struct clk gpt3_fck = {
 static struct clk gpt4_ick = {
        .name           = "gpt4_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT4_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT4_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt4_fck = {
        .name           = "gpt4_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT4_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT4_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1580,20 +1684,25 @@ static struct clk gpt4_fck = {
 static struct clk gpt5_ick = {
        .name           = "gpt5_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT5_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT5_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt5_fck = {
        .name           = "gpt5_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT5_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT5_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1602,20 +1711,25 @@ static struct clk gpt5_fck = {
 static struct clk gpt6_ick = {
        .name           = "gpt6_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT6_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT6_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt6_fck = {
        .name           = "gpt6_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT6_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT6_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1624,20 +1738,25 @@ static struct clk gpt6_fck = {
 static struct clk gpt7_ick = {
        .name           = "gpt7_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT7_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT7_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt7_fck = {
        .name           = "gpt7_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT7_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT7_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1646,20 +1765,25 @@ static struct clk gpt7_fck = {
 static struct clk gpt8_ick = {
        .name           = "gpt8_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT8_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT8_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt8_fck = {
        .name           = "gpt8_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT8_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT8_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1668,20 +1792,25 @@ static struct clk gpt8_fck = {
 static struct clk gpt9_ick = {
        .name           = "gpt9_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT9_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT9_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt9_fck = {
        .name           = "gpt9_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT9_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT9_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1690,20 +1819,25 @@ static struct clk gpt9_fck = {
 static struct clk gpt10_ick = {
        .name           = "gpt10_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT10_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT10_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt10_fck = {
        .name           = "gpt10_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT10_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT10_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1712,20 +1846,25 @@ static struct clk gpt10_fck = {
 static struct clk gpt11_ick = {
        .name           = "gpt11_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT11_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT11_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt11_fck = {
        .name           = "gpt11_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT11_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT11_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1734,20 +1873,25 @@ static struct clk gpt11_fck = {
 static struct clk gpt12_ick = {
        .name           = "gpt12_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT12_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPT12_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt12_fck = {
        .name           = "gpt12_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_GPT12_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL2),
+       .clksel_reg     = CM_CLKSEL2,
        .clksel_mask    = OMAP24XX_CLKSEL_GPT12_MASK,
        .clksel         = omap24xx_gpt_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -1757,9 +1901,12 @@ static struct clk mcbsp1_ick = {
        .name           = "mcbsp_ick",
        .id             = 1,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MCBSP1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1767,8 +1914,10 @@ static struct clk mcbsp1_fck = {
        .name           = "mcbsp_fck",
        .id             = 1,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_MCBSP1_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1777,9 +1926,12 @@ static struct clk mcbsp2_ick = {
        .name           = "mcbsp_ick",
        .id             = 2,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MCBSP2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1787,8 +1939,10 @@ static struct clk mcbsp2_fck = {
        .name           = "mcbsp_fck",
        .id             = 2,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_MCBSP2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1797,9 +1951,12 @@ static struct clk mcbsp3_ick = {
        .name           = "mcbsp_ick",
        .id             = 3,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP3_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MCBSP3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1807,8 +1964,10 @@ static struct clk mcbsp3_fck = {
        .name           = "mcbsp_fck",
        .id             = 3,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP3_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1817,9 +1976,12 @@ static struct clk mcbsp4_ick = {
        .name           = "mcbsp_ick",
        .id             = 4,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP4_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MCBSP4_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1827,8 +1989,10 @@ static struct clk mcbsp4_fck = {
        .name           = "mcbsp_fck",
        .id             = 4,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP4_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1837,9 +2001,12 @@ static struct clk mcbsp5_ick = {
        .name           = "mcbsp_ick",
        .id             = 5,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP5_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MCBSP5_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1847,8 +2014,10 @@ static struct clk mcbsp5_fck = {
        .name           = "mcbsp_fck",
        .id             = 5,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MCBSP5_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1857,9 +2026,12 @@ static struct clk mcspi1_ick = {
        .name           = "mcspi_ick",
        .id             = 1,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MCSPI1_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MCSPI1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1867,8 +2039,10 @@ static struct clk mcspi1_fck = {
        .name           = "mcspi_fck",
        .id             = 1,
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_MCSPI1_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1877,9 +2051,12 @@ static struct clk mcspi2_ick = {
        .name           = "mcspi_ick",
        .id             = 2,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MCSPI2_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MCSPI2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1887,8 +2064,10 @@ static struct clk mcspi2_fck = {
        .name           = "mcspi_fck",
        .id             = 2,
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_MCSPI2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1897,9 +2076,12 @@ static struct clk mcspi3_ick = {
        .name           = "mcspi_ick",
        .id             = 3,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MCSPI3_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MCSPI3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -1907,8 +2089,10 @@ static struct clk mcspi3_fck = {
        .name           = "mcspi_fck",
        .id             = 3,
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MCSPI3_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1916,17 +2100,22 @@ static struct clk mcspi3_fck = {
 static struct clk uart1_ick = {
        .name           = "uart1_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_UART1_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_UART1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart1_fck = {
        .name           = "uart1_fck",
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_UART1_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1934,17 +2123,22 @@ static struct clk uart1_fck = {
 static struct clk uart2_ick = {
        .name           = "uart2_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_UART2_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_UART2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart2_fck = {
        .name           = "uart2_fck",
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_UART2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1952,17 +2146,22 @@ static struct clk uart2_fck = {
 static struct clk uart3_ick = {
        .name           = "uart3_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP24XX_EN_UART3_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_UART3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart3_fck = {
        .name           = "uart3_fck",
        .parent         = &func_48m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP24XX_EN_UART3_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -1970,86 +2169,127 @@ static struct clk uart3_fck = {
 static struct clk gpios_ick = {
        .name           = "gpios_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_GPIOS_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPIOS_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpios_fck = {
        .name           = "gpios_fck",
        .parent         = &func_32k_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_EN_GPIOS_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_GPIOS_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
+/* aka WDT2 - REVISIT: we should split wu_l4_iclk from l4_ck */
 static struct clk mpu_wdt_ick = {
        .name           = "mpu_wdt_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_MPU_WDT_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MPU_WDT_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
+/* aka WDT2 */
 static struct clk mpu_wdt_fck = {
        .name           = "mpu_wdt_fck",
        .parent         = &func_32k_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP24XX_EN_MPU_WDT_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MPU_WDT_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk sync_32k_ick = {
        .name           = "sync_32k_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_32KSYNC_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_32KSYNC_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
+/* REVISIT: parent is really wu_l4_iclk */
 static struct clk wdt1_ick = {
        .name           = "wdt1_ick",
        .parent         = &l4_ck,
+       .prcm_mod       = WKUP_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .clkdm          = { .name = "prm_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_WDT1_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_WDT1_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
 static struct clk omapctrl_ick = {
        .name           = "omapctrl_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP24XX_EN_OMAPCTRL_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_OMAPCTRL_SHIFT,
        .recalc         = &followparent_recalc,
 };
+
 static struct clk icr_ick = {
        .name           = "icr_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP2430_EN_ICR_SHIFT,
+       .idlest_bit     = OMAP2430_ST_ICR_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk cam_ick = {
        .name           = "cam_ick",
        .parent         = &l4_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_CAM_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
+/*
+ * cam_fck controls both CAM_MCLK and CAM_FCLK.  It should probably be
+ * split into two separate clocks, since the parent clocks are different
+ * and the clockdomains are also different.
+ */
 static struct clk cam_fck = {
        .name           = "cam_fck",
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_CAM_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2057,26 +2297,34 @@ static struct clk cam_fck = {
 static struct clk mailboxes_ick = {
        .name           = "mailboxes_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MAILBOXES_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MAILBOXES_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt4_ick = {
        .name           = "wdt4_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_WDT4_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_WDT4_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt4_fck = {
        .name           = "wdt4_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_WDT4_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2084,108 +2332,144 @@ static struct clk wdt4_fck = {
 static struct clk wdt3_ick = {
        .name           = "wdt3_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_WDT3_SHIFT,
+       .idlest_bit     = OMAP2420_ST_WDT3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt3_fck = {
        .name           = "wdt3_fck",
        .parent         = &func_32k_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_WDT3_SHIFT,
+       .enable_bit     = OMAP2420_ST_WDT3_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mspro_ick = {
        .name           = "mspro_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_MSPRO_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MSPRO_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mspro_fck = {
        .name           = "mspro_fck",
        .parent         = &func_96m_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_MSPRO_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_MSPRO_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmc_ick = {
        .name           = "mmc_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_MMC_SHIFT,
+       .idlest_bit     = OMAP2420_ST_MMC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmc_fck = {
        .name           = "mmc_fck",
        .parent         = &func_96m_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_MMC_SHIFT,
+       .idlest_bit     = OMAP2420_ST_MMC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk fac_ick = {
        .name           = "fac_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_FAC_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_FAC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk fac_fck = {
        .name           = "fac_fck",
        .parent         = &func_12m_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_FAC_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_FAC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk eac_ick = {
        .name           = "eac_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_EAC_SHIFT,
+       .idlest_bit     = OMAP2420_ST_EAC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk eac_fck = {
        .name           = "eac_fck",
        .parent         = &func_96m_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_EAC_SHIFT,
+       .idlest_bit     = OMAP2420_ST_EAC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk hdq_ick = {
        .name           = "hdq_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP24XX_EN_HDQ_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_HDQ_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk hdq_fck = {
        .name           = "hdq_fck",
        .parent         = &func_12m_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP24XX_EN_HDQ_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_HDQ_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2193,9 +2477,12 @@ static struct clk i2c2_ick = {
        .name           = "i2c_ick",
        .id             = 2,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_I2C2_SHIFT,
+       .idlest_bit     = OMAP2420_ST_I2C2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2203,9 +2490,12 @@ static struct clk i2c2_fck = {
        .name           = "i2c_fck",
        .id             = 2,
        .parent         = &func_12m_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_I2C2_SHIFT,
+       .idlest_bit     = OMAP2420_ST_I2C2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2213,8 +2503,10 @@ static struct clk i2chs2_fck = {
        .name           = "i2chs_fck",
        .id             = 2,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_I2CHS2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2223,9 +2515,12 @@ static struct clk i2c1_ick = {
        .name           = "i2c_ick",
        .id             = 1,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_I2C1_SHIFT,
+       .idlest_bit     = OMAP2420_ST_I2C1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2233,9 +2528,12 @@ static struct clk i2c1_fck = {
        .name           = "i2c_fck",
        .id             = 1,
        .parent         = &func_12m_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_I2C1_SHIFT,
+       .idlest_bit     = OMAP2420_ST_I2C1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2243,8 +2541,10 @@ static struct clk i2chs1_fck = {
        .name           = "i2chs_fck",
        .id             = 1,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_I2CHS1_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2252,7 +2552,9 @@ static struct clk i2chs1_fck = {
 static struct clk gpmc_fck = {
        .name           = "gpmc_fck",
        .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
+       .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
+                               ENABLE_ON_INIT,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2260,6 +2562,7 @@ static struct clk sdma_fck = {
        .name           = "sdma_fck",
        .parent         = &core_l3_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2267,15 +2570,19 @@ static struct clk sdma_ick = {
        .name           = "sdma_ick",
        .parent         = &l4_ck,
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk vlynq_ick = {
        .name           = "vlynq_ick",
        .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP2420_EN_VLYNQ_SHIFT,
+       .idlest_bit     = OMAP2420_ST_VLYNQ_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
@@ -2307,11 +2614,14 @@ static const struct clksel vlynq_fck_clksel[] = {
 static struct clk vlynq_fck = {
        .name           = "vlynq_fck",
        .parent         = &func_96m_ck,
-       .flags          = CLOCK_IN_OMAP242X | DELAYED_APP,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP242X | DELAYED_APP | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP2420_EN_VLYNQ_SHIFT,
+       .idlest_bit     = OMAP2420_ST_VLYNQ_SHIFT,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP2420_CLKSEL_VLYNQ_MASK,
        .clksel         = vlynq_fck_clksel,
        .recalc         = &omap2_clksel_recalc,
@@ -2322,111 +2632,143 @@ static struct clk vlynq_fck = {
 static struct clk sdrc_ick = {
        .name           = "sdrc_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | ENABLE_ON_INIT,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY | ENABLE_ON_INIT,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN3,
        .enable_bit     = OMAP2430_EN_SDRC_SHIFT,
+       .idlest_bit     = OMAP2430_ST_SDRC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk des_ick = {
        .name           = "des_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_ICLKEN4,
        .enable_bit     = OMAP24XX_EN_DES_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_DES_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk sha_ick = {
        .name           = "sha_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_ICLKEN4,
        .enable_bit     = OMAP24XX_EN_SHA_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_SHA_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk rng_ick = {
        .name           = "rng_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_ICLKEN4,
        .enable_bit     = OMAP24XX_EN_RNG_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_RNG_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk aes_ick = {
        .name           = "aes_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_ICLKEN4,
        .enable_bit     = OMAP24XX_EN_AES_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_AES_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk pka_ick = {
        .name           = "pka_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_ICLKEN4),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_ICLKEN4,
        .enable_bit     = OMAP24XX_EN_PKA_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_PKA_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usb_fck = {
        .name           = "usb_fck",
        .parent         = &func_48m_ck,
-       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | CLOCK_IN_OMAP242X | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP24XX_EN_USB_SHIFT,
+       .idlest_bit     = OMAP24XX_ST_USB_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbhs_ick = {
        .name           = "usbhs_ick",
        .parent         = &core_l3_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_USBHS_SHIFT,
+       .idlest_bit     = OMAP2430_ST_USBHS_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs1_ick = {
        .name           = "mmchs_ick",
-       .id             = 1,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHS1_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MMCHS1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs1_fck = {
        .name           = "mmchs_fck",
-       .id             = 1,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHS1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs2_ick = {
        .name           = "mmchs_ick",
-       .id             = 2,
+       .id             = 1,
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHS2_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MMCHS2_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs2_fck = {
        .name           = "mmchs_fck",
-       .id             = 2,
+       .id             = 1,
        .parent         = &func_96m_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHS2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2434,17 +2776,22 @@ static struct clk mmchs2_fck = {
 static struct clk gpio5_ick = {
        .name           = "gpio5_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_GPIO5_SHIFT,
+       .idlest_bit     = OMAP2430_ST_GPIO5_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio5_fck = {
        .name           = "gpio5_fck",
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_GPIO5_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2452,28 +2799,34 @@ static struct clk gpio5_fck = {
 static struct clk mdm_intc_ick = {
        .name           = "mdm_intc_ick",
        .parent         = &l4_ck,
-       .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .flags          = CLOCK_IN_OMAP243X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP2430_EN_MDM_INTC_SHIFT,
+       .idlest_bit     = OMAP2430_ST_MDM_INTC_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchsdb1_fck = {
        .name           = "mmchsdb_fck",
-       .id             = 1,
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHSDB1_SHIFT,
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchsdb2_fck = {
        .name           = "mmchsdb_fck",
-       .id             = 2,
+       .id             = 1,
        .parent         = &func_32k_ck,
+       .prcm_mod       = CORE_MOD,
        .flags          = CLOCK_IN_OMAP243X,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2),
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .enable_reg     = OMAP24XX_CM_FCLKEN2,
        .enable_bit     = OMAP2430_EN_MMCHSDB2_SHIFT,
        .recalc         = &followparent_recalc,
 };
@@ -2496,6 +2849,7 @@ static struct clk virt_prcm_set = {
        .name           = "virt_prcm_set",
        .flags          = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
                                VIRTUAL_CLOCK | ALWAYS_ENABLED | DELAYED_APP,
+       .clkdm          = { .name = "virt_opp_clkdm" },
        .parent         = &mpu_ck,      /* Indexed by mpu speed, no parent */
        .recalc         = &omap2_table_mpu_recalc,      /* sets are keyed on mpu rate */
        .set_rate       = &omap2_select_table_rate,
index 3ff74952f8354658d310654fa32c894f3e6c2475..df258f762031bba6971e3eb9e7916dc2cd4a7913 100644 (file)
@@ -31,7 +31,7 @@
 #include <asm/div64.h>
 #include <asm/bitops.h>
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "clock.h"
 #include "clock34xx.h"
 #include "prm.h"
@@ -62,11 +62,14 @@ static void omap3_dpll_recalc(struct clk *clk)
 static void _omap3_dpll_write_clken(struct clk *clk, u8 clken_bits)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        dd = clk->dpll_data;
 
-       cm_rmw_reg_bits(dd->enable_mask, clken_bits << __ffs(dd->enable_mask),
-                       dd->control_reg);
+       v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
+       v &= ~dd->enable_mask;
+       v |= clken_bits << __ffs(dd->enable_mask);
+       cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
 }
 
 /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
@@ -75,14 +78,13 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
        const struct dpll_data *dd;
        int i = 0;
        int ret = -EINVAL;
-       u32 idlest_mask;
 
        dd = clk->dpll_data;
 
-       state <<= dd->idlest_bit;
-       idlest_mask = 1 << dd->idlest_bit;
+       state <<= __ffs(dd->idlest_mask);
 
-       while (((cm_read_reg(dd->idlest_reg) & idlest_mask) != state) &&
+       while (((cm_read_mod_reg(clk->prcm_mod, dd->idlest_reg)
+                & dd->idlest_mask) != state) &&
               i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
@@ -101,6 +103,42 @@ static int _omap3_wait_dpll_status(struct clk *clk, u8 state)
        return ret;
 }
 
+/* From 3430 TRM ES2 4.7.6.2 */
+static u16 _omap3_dpll_compute_freqsel(struct clk *clk, u8 n)
+{
+       unsigned long fint;
+       u16 f = 0;
+
+       fint = clk->parent->rate / (n + 1);
+
+       pr_debug("clock: fint is %lu\n", fint);
+
+       if (fint >= 750000 && fint <= 1000000)
+               f = 0x3;
+       else if (fint > 1000000 && fint <= 1250000)
+               f = 0x4;
+       else if (fint > 1250000 && fint <= 1500000)
+               f = 0x5;
+       else if (fint > 1500000 && fint <= 1750000)
+               f = 0x6;
+       else if (fint > 1750000 && fint <= 2100000)
+               f = 0x7;
+       else if (fint > 7500000 && fint <= 10000000)
+               f = 0xB;
+       else if (fint > 10000000 && fint <= 12500000)
+               f = 0xC;
+       else if (fint > 12500000 && fint <= 15000000)
+               f = 0xD;
+       else if (fint > 15000000 && fint <= 17500000)
+               f = 0xE;
+       else if (fint > 17500000 && fint <= 21000000)
+               f = 0xF;
+       else
+               pr_debug("clock: unknown freqsel setting for %d\n", n);
+
+       return f;
+}
+
 /* Non-CORE DPLL (e.g., DPLLs that do not control SDRC) clock functions */
 
 /*
@@ -143,7 +181,7 @@ static int _omap3_noncore_dpll_lock(struct clk *clk)
 }
 
 /*
- * omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
+ * _omap3_noncore_dpll_bypass - instruct a DPLL to bypass and wait for readiness
  * @clk: pointer to a DPLL struct clk
  *
  * Instructs a non-CORE DPLL to enter low-power bypass mode.  In
@@ -233,15 +271,24 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
 static int omap3_noncore_dpll_enable(struct clk *clk)
 {
        int r;
+       long rate;
+       struct dpll_data *dd;
 
        if (clk == &dpll3_ck)
                return -EINVAL;
 
-       if (clk->parent->rate == clk_get_rate(clk))
+       dd = clk->dpll_data;
+       if (!dd)
+               return -EINVAL;
+
+       if (clk->rate == dd->bypass_clk->rate)
                r = _omap3_noncore_dpll_bypass(clk);
        else
                r = _omap3_noncore_dpll_lock(clk);
 
+       if (!r)
+               clk->rate = rate;
+
        return r;
 }
 
@@ -267,6 +314,197 @@ static void omap3_noncore_dpll_disable(struct clk *clk)
        _omap3_noncore_dpll_stop(clk);
 }
 
+
+/* Non-CORE DPLL rate set code */
+
+/*
+ * omap3_noncore_dpll_program - set non-core DPLL M,N values directly
+ * @clk: struct clk * of DPLL to set
+ * @m: DPLL multiplier to set
+ * @n: DPLL divider to set
+ * @freqsel: FREQSEL value to set
+ *
+ * Program the DPLL with the supplied M, N values, and wait for the DPLL to
+ * lock..  Returns -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_noncore_dpll_program(struct clk *clk, u16 m, u8 n, u16 freqsel)
+{
+       struct dpll_data *dd;
+       u32 v;
+
+       if (!clk)
+               return -EINVAL;
+
+       dd = clk->dpll_data;
+       if (!dd)
+               return -EINVAL;
+
+       /*
+        * According to the 12-5 CDP code from TI, "Limitation 2.5"
+        * on 3430ES1 prevents us from changing DPLL multipliers or dividers
+        * on DPLL4.
+        */
+       if (system_rev == OMAP3430_REV_ES1_0 &&
+           !strcmp("dpll4_ck", clk->name)) {
+               printk(KERN_ERR "clock: DPLL4 cannot change rate due to "
+                      "silicon 'Limitation 2.5' on 3430ES1.\n");
+               return -EINVAL;
+       }
+
+       /* 3430 ES2 TRM: 4.7.6.9 DPLL Programming Sequence */
+       _omap3_noncore_dpll_bypass(clk);
+
+       /* Set jitter correction */
+       v = cm_read_mod_reg(clk->prcm_mod, dd->control_reg);
+       v &= ~dd->freqsel_mask;
+       v |= freqsel << __ffs(dd->freqsel_mask);
+       cm_write_mod_reg(v, clk->prcm_mod, dd->control_reg);
+
+       /* Set DPLL multiplier, divider */
+       v = cm_read_mod_reg(clk->prcm_mod, dd->mult_div1_reg);
+       v &= ~(dd->mult_mask | dd->div1_mask);
+       v |= m << __ffs(dd->mult_mask);
+       v |= (n - 1) << __ffs(dd->div1_mask);
+       cm_write_mod_reg(v, clk->prcm_mod, dd->mult_div1_reg);
+
+       /* We let the clock framework set the other output dividers later */
+
+       /* REVISIT: Set ramp-up delay? */
+
+       _omap3_noncore_dpll_lock(clk);
+
+       return 0;
+}
+
+/**
+ * omap3_noncore_dpll_set_rate - set non-core DPLL rate
+ * @clk: struct clk * of DPLL to set
+ * @rate: rounded target rate
+ *
+ * Set the DPLL CLKOUT to the target rate.  If the DPLL can enter
+ * low-power bypass, and the target rate is the bypass source clock
+ * rate, then configure the DPLL for bypass.  Otherwise, round the
+ * target rate if it hasn't been done already, then program and lock
+ * the DPLL.  Returns -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate)
+{
+       u16 freqsel;
+       struct dpll_data *dd;
+       int ret;
+
+       if (!clk || !rate)
+               return -EINVAL;
+
+       dd = clk->dpll_data;
+       if (!dd)
+               return -EINVAL;
+
+       if (rate == omap2_get_dpll_rate(clk))
+               return 0;
+
+       if (dd->bypass_clk->rate == rate &&
+           (clk->dpll_data->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+
+               pr_debug("clock: %s: set rate: entering bypass.\n", clk->name);
+
+               ret = _omap3_noncore_dpll_bypass(clk);
+               if (!ret)
+                       clk->rate = rate;
+
+       } else {
+
+               if (dd->last_rounded_rate != rate)
+                       omap2_dpll_round_rate(clk, rate);
+
+               if (dd->last_rounded_rate == 0)
+                       return -EINVAL;
+
+               freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
+               if (!freqsel)
+                       WARN_ON(1);
+
+               pr_debug("clock: %s: set rate: locking rate to %lu.\n",
+                        clk->name, rate);
+
+               ret = omap3_noncore_dpll_program(clk, dd->last_rounded_m,
+                                                dd->last_rounded_n, freqsel);
+
+       }
+
+       omap3_dpll_recalc(clk);
+
+       return 0;
+}
+
+
+/*
+ * CORE DPLL (DPLL3) rate programming functions
+ *
+ * These call into SRAM code to do the actual CM writes, since the SDRAM
+ * is clocked from DPLL3.
+ */
+
+/**
+ * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider
+ * @clk: struct clk * of DPLL to set
+ * @rate: rounded target rate
+ *
+ * Program the DPLL M2 divider with the rounded target rate.  Returns
+ * -EINVAL upon error, or 0 upon success.
+ */
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 new_div = 0;
+       unsigned long validrate, sdrcrate;
+       struct omap_sdrc_params *sp;
+
+       if (!clk || !rate)
+               return -EINVAL;
+
+       if (clk != &dpll3_m2_ck)
+               return -EINVAL;
+
+       if (rate == clk->rate)
+               return 0;
+
+       validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
+       if (validrate != rate)
+               return -EINVAL;
+
+       sdrcrate = sdrc_ick.rate;
+       if (rate > clk->rate)
+               sdrcrate <<= ((rate / clk->rate) - 1);
+       else
+               sdrcrate >>= ((clk->rate / rate) - 1);
+
+       sp = omap2_sdrc_get_params(sdrcrate);
+       if (!sp)
+               return -EINVAL;
+
+       pr_info("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate,
+               validrate);
+       pr_info("clock: SDRC timing params used: %08x %08x %08x\n",
+               sp->rfr_ctrl, sp->actim_ctrla, sp->actim_ctrlb);
+
+       /* REVISIT: SRAM code doesn't support other M2 divisors yet */
+       WARN_ON(new_div != 1 && new_div != 2);
+
+       /* REVISIT: Add SDRC_MR changing to this code also */
+       local_irq_disable();
+       omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla,
+                                 sp->actim_ctrlb, new_div);
+       local_irq_enable();
+
+       omap2_clksel_recalc(clk);
+
+       return 0;
+}
+
+
+/* DPLL autoidle read/set code */
+
+
 /**
  * omap3_dpll_autoidle_read - read a DPLL's autoidle bits
  * @clk: struct clk * of the DPLL to read
@@ -285,7 +523,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
 
        dd = clk->dpll_data;
 
-       v = cm_read_reg(dd->autoidle_reg);
+       v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
        v &= dd->autoidle_mask;
        v >>= __ffs(dd->autoidle_mask);
 
@@ -304,6 +542,7 @@ static u32 omap3_dpll_autoidle_read(struct clk *clk)
 static void omap3_dpll_allow_idle(struct clk *clk)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        if (!clk || !clk->dpll_data)
                return;
@@ -315,9 +554,10 @@ static void omap3_dpll_allow_idle(struct clk *clk)
         * by writing 0x5 instead of 0x1.  Add some mechanism to
         * optionally enter this mode.
         */
-       cm_rmw_reg_bits(dd->autoidle_mask,
-                       DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask),
-                       dd->autoidle_reg);
+       v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
+       v &= ~dd->autoidle_mask;
+       v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
+       cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
 }
 
 /**
@@ -329,15 +569,17 @@ static void omap3_dpll_allow_idle(struct clk *clk)
 static void omap3_dpll_deny_idle(struct clk *clk)
 {
        const struct dpll_data *dd;
+       u32 v;
 
        if (!clk || !clk->dpll_data)
                return;
 
        dd = clk->dpll_data;
 
-       cm_rmw_reg_bits(dd->autoidle_mask,
-                       DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask),
-                       dd->autoidle_reg);
+       v = cm_read_mod_reg(clk->prcm_mod, dd->autoidle_reg);
+       v &= ~dd->autoidle_mask;
+       v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
+       cm_write_mod_reg(v, clk->prcm_mod, dd->autoidle_reg);
 }
 
 /* Clock control for DPLL outputs */
@@ -365,11 +607,10 @@ static void omap3_clkoutx2_recalc(struct clk *clk)
 
        dd = pclk->dpll_data;
 
-       WARN_ON(!dd->control_reg || !dd->enable_mask);
+       WARN_ON(!dd->idlest_reg || !dd->idlest_mask);
 
-       v = __raw_readl(dd->control_reg) & dd->enable_mask;
-       v >>= __ffs(dd->enable_mask);
-       if (v != DPLL_LOCKED)
+       v = cm_read_mod_reg(pclk->prcm_mod, dd->idlest_reg) & dd->idlest_mask;
+       if (!v)
                clk->rate = clk->parent->rate;
        else
                clk->rate = clk->parent->rate * 2;
@@ -468,7 +709,7 @@ int __init omap2_clk_init(void)
                 * Update this if there are further clock changes between ES2
                 * and production parts
                 */
-               if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {
+               if (system_rev == OMAP3430_REV_ES1_0) {
                        /* No 3430ES1-only rates exist, so no RATE_IN_3430ES1 */
                        cpu_clkflg |= CLOCK_IN_OMAP3430ES1;
                } else {
@@ -482,8 +723,10 @@ int __init omap2_clk_init(void)
        for (clkp = onchip_34xx_clks;
             clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
             clkp++) {
-               if ((*clkp)->flags & cpu_clkflg)
+               if ((*clkp)->flags & cpu_clkflg) {
                        clk_register(*clkp);
+                       omap2_init_clk_clkdm(*clkp);
+               }
        }
 
        /* REVISIT: Not yet ready for OMAP3 */
index ec664457a11a964b88b5f7cf8dd10d882f082588..08789c8997fcf2f7eb1681599e960d41934fe989 100644 (file)
@@ -34,6 +34,8 @@ static void omap3_dpll_deny_idle(struct clk *clk);
 static u32 omap3_dpll_autoidle_read(struct clk *clk);
 static int omap3_noncore_dpll_enable(struct clk *clk);
 static void omap3_noncore_dpll_disable(struct clk *clk);
+static int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate);
+static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate);
 
 /* Maximum DPLL multiplier, divider values for OMAP3 */
 #define OMAP3_MAX_DPLL_MULT            2048
@@ -47,6 +49,10 @@ static void omap3_noncore_dpll_disable(struct clk *clk);
  * DPLL5 supplies other peripheral clocks (USBHOST, USIM).
  */
 
+/* Forward declarations for DPLL bypass clocks */
+static struct clk dpll1_fck;
+static struct clk dpll2_fck;
+
 /* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
 #define DPLL_LOW_POWER_STOP            0x1
 #define DPLL_LOW_POWER_BYPASS          0x5
@@ -60,6 +66,7 @@ static struct clk omap_32k_fck = {
        .rate           = 32768,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -68,6 +75,7 @@ static struct clk secure_32k_fck = {
        .rate           = 32768,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -77,6 +85,7 @@ static struct clk virt_12m_ck = {
        .rate           = 12000000,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -85,6 +94,7 @@ static struct clk virt_13m_ck = {
        .rate           = 13000000,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -93,6 +103,7 @@ static struct clk virt_16_8m_ck = {
        .rate           = 16800000,
        .flags          = CLOCK_IN_OMAP3430ES2 | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -101,6 +112,7 @@ static struct clk virt_19_2m_ck = {
        .rate           = 19200000,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -109,6 +121,7 @@ static struct clk virt_26m_ck = {
        .rate           = 26000000,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -117,6 +130,7 @@ static struct clk virt_38_4m_ck = {
        .rate           = 38400000,
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -164,13 +178,15 @@ static const struct clksel osc_sys_clksel[] = {
 /* 12, 13, 16.8, 19.2, 26, or 38.4 MHz */
 static struct clk osc_sys_ck = {
        .name           = "osc_sys_ck",
+       .prcm_mod       = OMAP3430_CCR_MOD | CLK_REG_IN_PRM,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP3430_PRM_CLKSEL,
+       .clksel_reg     = OMAP3_PRM_CLKSEL_OFFSET,
        .clksel_mask    = OMAP3430_SYS_CLKIN_SEL_MASK,
        .clksel         = osc_sys_clksel,
        /* REVISIT: deal with autoextclkmode? */
        .flags          = CLOCK_IN_OMAP343X | RATE_FIXED | RATE_PROPAGATES |
                                ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -190,24 +206,32 @@ static const struct clksel sys_clksel[] = {
 static struct clk sys_ck = {
        .name           = "sys_ck",
        .parent         = &osc_sys_ck,
+       .prcm_mod       = OMAP3430_GR_MOD | CLK_REG_IN_PRM,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP3430_PRM_CLKSRC_CTRL,
+       .clksel_reg     = OMAP3_PRM_CLKSRC_CTRL_OFFSET,
        .clksel_mask    = OMAP_SYSCLKDIV_MASK,
        .clksel         = sys_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk sys_altclk = {
        .name           = "sys_altclk",
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
-/* Optional external clock input for some McBSPs */
+/*
+ * Optional external clock input for some McBSPs
+ * Apparently this is not really in prm_clkdm, but rather is fed into
+ * both CORE and PER separately.
+ */
 static struct clk mcbsp_clks = {
        .name           = "mcbsp_clks",
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &propagate_rate,
 };
 
@@ -216,9 +240,11 @@ static struct clk mcbsp_clks = {
 static struct clk sys_clkout1 = {
        .name           = "sys_clkout1",
        .parent         = &osc_sys_ck,
-       .enable_reg     = OMAP3430_PRM_CLKOUT_CTRL,
+       .prcm_mod       = OMAP3430_CCR_MOD | CLK_REG_IN_PRM,
+       .enable_reg     = OMAP3_PRM_CLKOUT_CTRL_OFFSET,
        .enable_bit     = OMAP3430_CLKOUT_EN_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -226,16 +252,6 @@ static struct clk sys_clkout1 = {
 
 /* CM CLOCKS */
 
-static const struct clksel_rate dpll_bypass_rates[] = {
-       { .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
-       { .div = 0 }
-};
-
-static const struct clksel_rate dpll_locked_rates[] = {
-       { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
-       { .div = 0 }
-};
-
 static const struct clksel_rate div16_dpll_rates[] = {
        { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
        { .div = 2, .val = 2, .flags = RATE_IN_343X },
@@ -260,19 +276,21 @@ static const struct clksel_rate div16_dpll_rates[] = {
 /* MPU clock source */
 /* Type: DPLL */
 static struct dpll_data dpll1_dd = {
-       .mult_div1_reg  = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
+       .mult_div1_reg  = OMAP3430_CM_CLKSEL1_PLL,
        .mult_mask      = OMAP3430_MPU_DPLL_MULT_MASK,
        .div1_mask      = OMAP3430_MPU_DPLL_DIV_MASK,
-       .control_reg    = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKEN_PLL),
+       .freqsel_mask   = OMAP3430_MPU_DPLL_FREQSEL_MASK,
+       .control_reg    = OMAP3430_CM_CLKEN_PLL,
        .enable_mask    = OMAP3430_EN_MPU_DPLL_MASK,
        .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
        .auto_recal_bit = OMAP3430_EN_MPU_DPLL_DRIFTGUARD_SHIFT,
        .recal_en_bit   = OMAP3430_MPU_DPLL_RECAL_EN_SHIFT,
        .recal_st_bit   = OMAP3430_MPU_DPLL_ST_SHIFT,
-       .autoidle_reg   = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL),
+       .autoidle_reg   = OMAP3430_CM_AUTOIDLE_PLL,
        .autoidle_mask  = OMAP3430_AUTO_MPU_DPLL_MASK,
-       .idlest_reg     = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
-       .idlest_bit     = OMAP3430_ST_MPU_CLK_SHIFT,
+       .idlest_reg     = OMAP3430_CM_IDLEST_PLL,
+       .idlest_mask    = OMAP3430_ST_MPU_CLK_MASK,
+       .bypass_clk     = &dpll1_fck,
        .max_multiplier = OMAP3_MAX_DPLL_MULT,
        .max_divider    = OMAP3_MAX_DPLL_DIV,
        .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
@@ -281,9 +299,12 @@ static struct dpll_data dpll1_dd = {
 static struct clk dpll1_ck = {
        .name           = "dpll1_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = MPU_MOD,
        .dpll_data      = &dpll1_dd,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
        .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .clkdm          = { .name = "dpll1_clkdm" },
        .recalc         = &omap3_dpll_recalc,
 };
 
@@ -296,6 +317,7 @@ static struct clk dpll1_x2_ck = {
        .parent         = &dpll1_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll1_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -312,12 +334,14 @@ static const struct clksel div16_dpll1_x2m2_clksel[] = {
 static struct clk dpll1_x2m2_ck = {
        .name           = "dpll1_x2m2_ck",
        .parent         = &dpll1_x2_ck,
+       .prcm_mod       = MPU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL),
+       .clksel_reg     = OMAP3430_CM_CLKSEL2_PLL,
        .clksel_mask    = OMAP3430_MPU_DPLL_CLKOUT_DIV_MASK,
        .clksel         = div16_dpll1_x2m2_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll1_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -326,20 +350,22 @@ static struct clk dpll1_x2m2_ck = {
 /* Type: DPLL */
 
 static struct dpll_data dpll2_dd = {
-       .mult_div1_reg  = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
+       .mult_div1_reg  = OMAP3430_CM_CLKSEL1_PLL,
        .mult_mask      = OMAP3430_IVA2_DPLL_MULT_MASK,
        .div1_mask      = OMAP3430_IVA2_DPLL_DIV_MASK,
-       .control_reg    = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL),
+       .freqsel_mask   = OMAP3430_IVA2_DPLL_FREQSEL_MASK,
+       .control_reg    = OMAP3430_CM_CLKEN_PLL,
        .enable_mask    = OMAP3430_EN_IVA2_DPLL_MASK,
        .modes          = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED) |
                                (1 << DPLL_LOW_POWER_BYPASS),
        .auto_recal_bit = OMAP3430_EN_IVA2_DPLL_DRIFTGUARD_SHIFT,
        .recal_en_bit   = OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT,
        .recal_st_bit   = OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT,
-       .autoidle_reg   = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_AUTOIDLE_PLL),
+       .autoidle_reg   = OMAP3430_CM_AUTOIDLE_PLL,
        .autoidle_mask  = OMAP3430_AUTO_IVA2_DPLL_MASK,
-       .idlest_reg     = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_IDLEST_PLL),
-       .idlest_bit     = OMAP3430_ST_IVA2_CLK_SHIFT,
+       .idlest_reg     = OMAP3430_CM_IDLEST_PLL,
+       .idlest_mask    = OMAP3430_ST_IVA2_CLK_MASK,
+       .bypass_clk     = &dpll2_fck,
        .max_multiplier = OMAP3_MAX_DPLL_MULT,
        .max_divider    = OMAP3_MAX_DPLL_DIV,
        .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
@@ -348,11 +374,14 @@ static struct dpll_data dpll2_dd = {
 static struct clk dpll2_ck = {
        .name           = "dpll2_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = OMAP3430_IVA2_MOD,
        .dpll_data      = &dpll2_dd,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
        .enable         = &omap3_noncore_dpll_enable,
        .disable        = &omap3_noncore_dpll_disable,
        .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .clkdm          = { .name = "dpll2_clkdm" },
        .recalc         = &omap3_dpll_recalc,
 };
 
@@ -368,13 +397,14 @@ static const struct clksel div16_dpll2_m2x2_clksel[] = {
 static struct clk dpll2_m2_ck = {
        .name           = "dpll2_m2_ck",
        .parent         = &dpll2_ck,
+       .prcm_mod       = OMAP3430_IVA2_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD,
-                                         OMAP3430_CM_CLKSEL2_PLL),
+       .clksel_reg     = OMAP3430_CM_CLKSEL2_PLL,
        .clksel_mask    = OMAP3430_IVA2_DPLL_CLKOUT_DIV_MASK,
        .clksel         = div16_dpll2_m2x2_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll2_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -384,16 +414,20 @@ static struct clk dpll2_m2_ck = {
  * REVISIT: Also supports fast relock bypass - not included below
  */
 static struct dpll_data dpll3_dd = {
-       .mult_div1_reg  = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .mult_div1_reg  = CM_CLKSEL1,
        .mult_mask      = OMAP3430_CORE_DPLL_MULT_MASK,
        .div1_mask      = OMAP3430_CORE_DPLL_DIV_MASK,
-       .control_reg    = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .freqsel_mask   = OMAP3430_CORE_DPLL_FREQSEL_MASK,
+       .control_reg    = CM_CLKEN,
        .enable_mask    = OMAP3430_EN_CORE_DPLL_MASK,
        .auto_recal_bit = OMAP3430_EN_CORE_DPLL_DRIFTGUARD_SHIFT,
        .recal_en_bit   = OMAP3430_CORE_DPLL_RECAL_EN_SHIFT,
        .recal_st_bit   = OMAP3430_CORE_DPLL_ST_SHIFT,
-       .autoidle_reg   = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
+       .autoidle_reg   = CM_AUTOIDLE,
        .autoidle_mask  = OMAP3430_AUTO_CORE_DPLL_MASK,
+       .idlest_reg     = CM_IDLEST,
+       .idlest_mask    = OMAP3430_ST_CORE_CLK_MASK,
+       .bypass_clk     = &sys_ck,
        .max_multiplier = OMAP3_MAX_DPLL_MULT,
        .max_divider    = OMAP3_MAX_DPLL_DIV,
        .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
@@ -402,9 +436,11 @@ static struct dpll_data dpll3_dd = {
 static struct clk dpll3_ck = {
        .name           = "dpll3_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .dpll_data      = &dpll3_dd,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
        .round_rate     = &omap2_dpll_round_rate,
+       .clkdm          = { .name = "dpll3_clkdm" },
        .recalc         = &omap3_dpll_recalc,
 };
 
@@ -417,6 +453,7 @@ static struct clk dpll3_x2_ck = {
        .parent         = &dpll3_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll3_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -460,55 +497,39 @@ static const struct clksel div31_dpll3m2_clksel[] = {
        { .parent = NULL }
 };
 
-/*
- * DPLL3 output M2
- * REVISIT: This DPLL output divider must be changed in SRAM, so until
- * that code is ready, this should remain a 'read-only' clksel clock.
- */
+/* DPLL3 output M2 - primary control point for CORE speed */
 static struct clk dpll3_m2_ck = {
        .name           = "dpll3_m2_ck",
        .parent         = &dpll3_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_CORE_DPLL_CLKOUT_DIV_MASK,
        .clksel         = div31_dpll3m2_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll3_clkdm" },
+       .round_rate     = &omap2_clksel_round_rate,
+       .set_rate       = &omap3_core_dpll_m2_set_rate,
        .recalc         = &omap2_clksel_recalc,
 };
 
-static const struct clksel core_ck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
-       { .parent = &dpll3_m2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
 static struct clk core_ck = {
        .name           = "core_ck",
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_CORE_CLK_MASK,
-       .clksel         = core_ck_clksel,
+       .parent         = &dpll3_m2_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
-};
-
-static const struct clksel dpll3_m2x2_ck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
-       { .parent = &dpll3_x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
+       .clkdm          = { .name = "cm_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 static struct clk dpll3_m2x2_ck = {
        .name           = "dpll3_m2x2_ck",
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_CORE_CLK_MASK,
-       .clksel         = dpll3_m2x2_ck_clksel,
+       .parent         = &dpll3_x2_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
+       .clkdm          = { .name = "dpll3_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 /* The PWRDN bit is apparently only available on 3430ES2 and above */
@@ -521,12 +542,14 @@ static const struct clksel div16_dpll3_clksel[] = {
 static struct clk dpll3_m3_ck = {
        .name           = "dpll3_m3_ck",
        .parent         = &dpll3_ck,
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_DIV_DPLL3_MASK,
        .clksel         = div16_dpll3_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll3_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -534,47 +557,42 @@ static struct clk dpll3_m3_ck = {
 static struct clk dpll3_m3x2_ck = {
        .name           = "dpll3_m3x2_ck",
        .parent         = &dpll3_m3_ck,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .prcm_mod       = PLL_MOD,
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP3430_PWRDN_EMU_CORE_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll3_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
-static const struct clksel emu_core_alwon_ck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll3_m3x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
 static struct clk emu_core_alwon_ck = {
        .name           = "emu_core_alwon_ck",
        .parent         = &dpll3_m3x2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_CORE_CLK_MASK,
-       .clksel         = emu_core_alwon_ck_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
+       .clkdm          = { .name = "dpll3_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 /* DPLL4 */
 /* Supplies 96MHz, 54Mhz TV DAC, DSS fclk, CAM sensor clock, emul trace clk */
 /* Type: DPLL */
 static struct dpll_data dpll4_dd = {
-       .mult_div1_reg  = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL2),
+       .mult_div1_reg  = CM_CLKSEL2,
        .mult_mask      = OMAP3430_PERIPH_DPLL_MULT_MASK,
        .div1_mask      = OMAP3430_PERIPH_DPLL_DIV_MASK,
-       .control_reg    = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .freqsel_mask   = OMAP3430_PERIPH_DPLL_FREQSEL_MASK,
+       .control_reg    = CM_CLKEN,
        .enable_mask    = OMAP3430_EN_PERIPH_DPLL_MASK,
        .modes          = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
        .auto_recal_bit = OMAP3430_EN_PERIPH_DPLL_DRIFTGUARD_SHIFT,
        .recal_en_bit   = OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT,
        .recal_st_bit   = OMAP3430_PERIPH_DPLL_ST_SHIFT,
-       .autoidle_reg   = OMAP_CM_REGADDR(PLL_MOD, CM_AUTOIDLE),
+       .autoidle_reg   = CM_AUTOIDLE,
        .autoidle_mask  = OMAP3430_AUTO_PERIPH_DPLL_MASK,
-       .idlest_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .idlest_bit     = OMAP3430_ST_PERIPH_CLK_SHIFT,
+       .idlest_reg     = CM_IDLEST,
+       .idlest_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
+       .bypass_clk     = &sys_ck,
        .max_multiplier = OMAP3_MAX_DPLL_MULT,
        .max_divider    = OMAP3_MAX_DPLL_DIV,
        .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
@@ -583,11 +601,14 @@ static struct dpll_data dpll4_dd = {
 static struct clk dpll4_ck = {
        .name           = "dpll4_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .dpll_data      = &dpll4_dd,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
        .enable         = &omap3_noncore_dpll_enable,
        .disable        = &omap3_noncore_dpll_disable,
        .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_dpll_recalc,
 };
 
@@ -601,6 +622,7 @@ static struct clk dpll4_x2_ck = {
        .parent         = &dpll4_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -613,12 +635,14 @@ static const struct clksel div16_dpll4_clksel[] = {
 static struct clk dpll4_m2_ck = {
        .name           = "dpll4_m2_ck",
        .parent         = &dpll4_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, OMAP3430_CM_CLKSEL3),
+       .clksel_reg     = OMAP3430_CM_CLKSEL3,
        .clksel_mask    = OMAP3430_DIV_96M_MASK,
        .clksel         = div16_dpll4_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -626,53 +650,65 @@ static struct clk dpll4_m2_ck = {
 static struct clk dpll4_m2x2_ck = {
        .name           = "dpll4_m2x2_ck",
        .parent         = &dpll4_m2_ck,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .prcm_mod       = PLL_MOD,
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP3430_PWRDN_96M_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
-static const struct clksel omap_96m_alwon_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
+/*
+ * DPLL4 generates DPLL4_M2X2_CLK which is then routed into the PRM as
+ * PRM_96M_ALWON_(F)CLK.  Two clocks then emerge from the PRM:
+ * 96M_ALWON_FCLK (called "omap_96m_alwon_fck" below) and
+ * CM_96K_(F)CLK.
+ */
 static struct clk omap_96m_alwon_fck = {
        .name           = "omap_96m_alwon_fck",
        .parent         = &dpll4_m2x2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
-       .clksel         = omap_96m_alwon_fck_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
-                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
+                               PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "prm_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
-static struct clk omap_96m_fck = {
-       .name           = "omap_96m_fck",
+static struct clk cm_96m_fck = {
+       .name           = "cm_96m_fck",
        .parent         = &omap_96m_alwon_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static const struct clksel cm_96m_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll4_m2x2_ck, .rates = dpll_locked_rates },
+static const struct clksel_rate omap_96m_dpll_rates[] = {
+       { .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
+       { .div = 0 }
+};
+
+static const struct clksel_rate omap_96m_sys_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
+       { .div = 0 }
+};
+
+static const struct clksel omap_96m_fck_clksel[] = {
+       { .parent = &cm_96m_fck, .rates = omap_96m_dpll_rates },
+       { .parent = &sys_ck,     .rates = omap_96m_sys_rates },
        { .parent = NULL }
 };
 
-static struct clk cm_96m_fck = {
-       .name           = "cm_96m_fck",
-       .parent         = &dpll4_m2x2_ck,
+static struct clk omap_96m_fck = {
+       .name           = "omap_96m_fck",
+       .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
-       .clksel         = cm_96m_fck_clksel,
+       .clksel_reg     = CM_CLKSEL1,
+       .clksel_mask    = OMAP3430_SOURCE_96M_MASK,
+       .clksel         = omap_96m_fck_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -680,12 +716,14 @@ static struct clk cm_96m_fck = {
 static struct clk dpll4_m3_ck = {
        .name           = "dpll4_m3_ck",
        .parent         = &dpll4_ck,
+       .prcm_mod       = OMAP3430_DSS_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_TV_MASK,
        .clksel         = div16_dpll4_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -693,31 +731,15 @@ static struct clk dpll4_m3_ck = {
 static struct clk dpll4_m3x2_ck = {
        .name           = "dpll4_m3x2_ck",
        .parent         = &dpll4_m3_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP3430_PWRDN_TV_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
-static const struct clksel virt_omap_54m_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll4_m3x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
-static struct clk virt_omap_54m_fck = {
-       .name           = "virt_omap_54m_fck",
-       .parent         = &dpll4_m3x2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
-       .clksel         = virt_omap_54m_fck_clksel,
-       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
-                               PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
-};
-
 static const struct clksel_rate omap_54m_d4m3x2_rates[] = {
        { .div = 1, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
        { .div = 0 }
@@ -729,23 +751,25 @@ static const struct clksel_rate omap_54m_alt_rates[] = {
 };
 
 static const struct clksel omap_54m_clksel[] = {
-       { .parent = &virt_omap_54m_fck, .rates = omap_54m_d4m3x2_rates },
+       { .parent = &dpll4_m3x2_ck, .rates = omap_54m_d4m3x2_rates },
        { .parent = &sys_altclk,    .rates = omap_54m_alt_rates },
        { .parent = NULL }
 };
 
 static struct clk omap_54m_fck = {
        .name           = "omap_54m_fck",
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
-       .clksel_mask    = OMAP3430_SOURCE_54M,
+       .clksel_reg     = CM_CLKSEL1,
+       .clksel_mask    = OMAP3430_SOURCE_54M_MASK,
        .clksel         = omap_54m_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static const struct clksel_rate omap_48m_96md2_rates[] = {
+static const struct clksel_rate omap_48m_cm96m_rates[] = {
        { .div = 2, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
        { .div = 0 }
 };
@@ -756,19 +780,21 @@ static const struct clksel_rate omap_48m_alt_rates[] = {
 };
 
 static const struct clksel omap_48m_clksel[] = {
-       { .parent = &cm_96m_fck, .rates = omap_48m_96md2_rates },
+       { .parent = &cm_96m_fck, .rates = omap_48m_cm96m_rates },
        { .parent = &sys_altclk, .rates = omap_48m_alt_rates },
        { .parent = NULL }
 };
 
 static struct clk omap_48m_fck = {
        .name           = "omap_48m_fck",
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1),
-       .clksel_mask    = OMAP3430_SOURCE_48M,
+       .clksel_reg     = CM_CLKSEL1,
+       .clksel_mask    = OMAP3430_SOURCE_48M_MASK,
        .clksel         = omap_48m_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -778,6 +804,7 @@ static struct clk omap_12m_fck = {
        .fixed_div      = 4,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_fixed_divisor_recalc,
 };
 
@@ -785,12 +812,14 @@ static struct clk omap_12m_fck = {
 static struct clk dpll4_m4_ck = {
        .name           = "dpll4_m4_ck",
        .parent         = &dpll4_ck,
+       .prcm_mod       = OMAP3430_DSS_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_DSS1_MASK,
        .clksel         = div16_dpll4_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -798,9 +827,11 @@ static struct clk dpll4_m4_ck = {
 static struct clk dpll4_m4x2_ck = {
        .name           = "dpll4_m4x2_ck",
        .parent         = &dpll4_m4_ck,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
-       .enable_bit     = OMAP3430_PWRDN_CAM_SHIFT,
+       .prcm_mod       = PLL_MOD,
+       .enable_reg     = CM_CLKEN,
+       .enable_bit     = OMAP3430_PWRDN_DSS1_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -808,12 +839,14 @@ static struct clk dpll4_m4x2_ck = {
 static struct clk dpll4_m5_ck = {
        .name           = "dpll4_m5_ck",
        .parent         = &dpll4_ck,
+       .prcm_mod       = OMAP3430_CAM_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_CAM_MASK,
        .clksel         = div16_dpll4_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -821,9 +854,11 @@ static struct clk dpll4_m5_ck = {
 static struct clk dpll4_m5x2_ck = {
        .name           = "dpll4_m5x2_ck",
        .parent         = &dpll4_m5_ck,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .prcm_mod       = PLL_MOD,
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP3430_PWRDN_CAM_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -831,12 +866,14 @@ static struct clk dpll4_m5x2_ck = {
 static struct clk dpll4_m6_ck = {
        .name           = "dpll4_m6_ck",
        .parent         = &dpll4_ck,
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_DIV_DPLL4_MASK,
        .clksel         = div16_dpll4_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -844,10 +881,12 @@ static struct clk dpll4_m6_ck = {
 static struct clk dpll4_m6x2_ck = {
        .name           = "dpll4_m6x2_ck",
        .parent         = &dpll4_m6_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN),
+       .enable_reg     = CM_CLKEN,
        .enable_bit     = OMAP3430_PWRDN_EMU_PERIPH_SHIFT,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | INVERT_ENABLE,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &omap3_clkoutx2_recalc,
 };
 
@@ -856,6 +895,7 @@ static struct clk emu_per_alwon_ck = {
        .parent         = &dpll4_m6x2_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -864,19 +904,21 @@ static struct clk emu_per_alwon_ck = {
 /* Type: DPLL */
 /* 3430ES2 only */
 static struct dpll_data dpll5_dd = {
-       .mult_div1_reg  = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL4),
+       .mult_div1_reg  = OMAP3430ES2_CM_CLKSEL4,
        .mult_mask      = OMAP3430ES2_PERIPH2_DPLL_MULT_MASK,
        .div1_mask      = OMAP3430ES2_PERIPH2_DPLL_DIV_MASK,
-       .control_reg    = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKEN2),
+       .freqsel_mask   = OMAP3430ES2_PERIPH2_DPLL_FREQSEL_MASK,
+       .control_reg    = OMAP3430ES2_CM_CLKEN2,
        .enable_mask    = OMAP3430ES2_EN_PERIPH2_DPLL_MASK,
        .modes          = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
        .auto_recal_bit = OMAP3430ES2_EN_PERIPH2_DPLL_DRIFTGUARD_SHIFT,
        .recal_en_bit   = OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT,
        .recal_st_bit   = OMAP3430ES2_SND_PERIPH_DPLL_ST_SHIFT,
-       .autoidle_reg   = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_AUTOIDLE2_PLL),
+       .autoidle_reg   = OMAP3430ES2_CM_AUTOIDLE2_PLL,
        .autoidle_mask  = OMAP3430ES2_AUTO_PERIPH2_DPLL_MASK,
-       .idlest_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
-       .idlest_bit     = OMAP3430ES2_ST_PERIPH2_CLK_SHIFT,
+       .idlest_reg     = CM_IDLEST2,
+       .idlest_mask    = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
+       .bypass_clk     = &sys_ck,
        .max_multiplier = OMAP3_MAX_DPLL_MULT,
        .max_divider    = OMAP3_MAX_DPLL_DIV,
        .rate_tolerance = DEFAULT_DPLL_RATE_TOLERANCE
@@ -885,11 +927,14 @@ static struct dpll_data dpll5_dd = {
 static struct clk dpll5_ck = {
        .name           = "dpll5_ck",
        .parent         = &sys_ck,
+       .prcm_mod       = PLL_MOD,
        .dpll_data      = &dpll5_dd,
        .flags          = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES,
        .enable         = &omap3_noncore_dpll_enable,
        .disable        = &omap3_noncore_dpll_disable,
        .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .clkdm          = { .name = "dpll5_clkdm" },
        .recalc         = &omap3_dpll_recalc,
 };
 
@@ -901,33 +946,17 @@ static const struct clksel div16_dpll5_clksel[] = {
 static struct clk dpll5_m2_ck = {
        .name           = "dpll5_m2_ck",
        .parent         = &dpll5_ck,
+       .prcm_mod       = PLL_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, OMAP3430ES2_CM_CLKSEL5),
+       .clksel_reg     = OMAP3430ES2_CM_CLKSEL5,
        .clksel_mask    = OMAP3430ES2_DIV_120M_MASK,
        .clksel         = div16_dpll5_clksel,
        .flags          = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "dpll5_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static const struct clksel omap_120m_fck_clksel[] = {
-       { .parent = &sys_ck,      .rates = dpll_bypass_rates },
-       { .parent = &dpll5_m2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
-static struct clk omap_120m_fck = {
-       .name           = "omap_120m_fck",
-       .parent         = &dpll5_m2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST2),
-       .clksel_mask    = OMAP3430ES2_ST_PERIPH2_CLK_MASK,
-       .clksel         = omap_120m_fck_clksel,
-       .flags          = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES |
-                               PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
-};
-
 /* CM EXTERNAL CLOCK OUTPUTS */
 
 static const struct clksel_rate clkout2_src_core_rates[] = {
@@ -951,22 +980,24 @@ static const struct clksel_rate clkout2_src_54m_rates[] = {
 };
 
 static const struct clksel clkout2_src_clksel[] = {
-       { .parent = &core_ck,             .rates = clkout2_src_core_rates },
-       { .parent = &sys_ck,              .rates = clkout2_src_sys_rates },
-       { .parent = &omap_96m_alwon_fck,  .rates = clkout2_src_96m_rates },
-       { .parent = &omap_54m_fck,        .rates = clkout2_src_54m_rates },
+       { .parent = &core_ck,           .rates = clkout2_src_core_rates },
+       { .parent = &sys_ck,            .rates = clkout2_src_sys_rates },
+       { .parent = &cm_96m_fck,        .rates = clkout2_src_96m_rates },
+       { .parent = &omap_54m_fck,      .rates = clkout2_src_54m_rates },
        { .parent = NULL }
 };
 
 static struct clk clkout2_src_ck = {
        .name           = "clkout2_src_ck",
+       .prcm_mod       = OMAP3430_CCR_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP3430_CM_CLKOUT_CTRL,
+       .enable_reg     = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
        .enable_bit     = OMAP3430_CLKOUT2_EN_SHIFT,
-       .clksel_reg     = OMAP3430_CM_CLKOUT_CTRL,
+       .clksel_reg     = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP3430_CLKOUT2SOURCE_MASK,
        .clksel         = clkout2_src_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -986,11 +1017,13 @@ static const struct clksel sys_clkout2_clksel[] = {
 
 static struct clk sys_clkout2 = {
        .name           = "sys_clkout2",
+       .prcm_mod       = OMAP3430_CCR_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP3430_CM_CLKOUT_CTRL,
+       .clksel_reg     = OMAP3430_CM_CLKOUT_CTRL_OFFSET,
        .clksel_mask    = OMAP3430_CLKOUT2_DIV_MASK,
        .clksel         = sys_clkout2_clksel,
        .flags          = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1001,54 +1034,45 @@ static struct clk corex2_fck = {
        .parent         = &dpll3_m2x2_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 /* DPLL power domain clock controls */
 
-static const struct clksel div2_core_clksel[] = {
-       { .parent = &core_ck, .rates = div2_rates },
+static const struct clksel_rate div4_rates[] = {
+       { .div = 1, .val = 1, .flags = RATE_IN_343X | DEFAULT_RATE },
+       { .div = 2, .val = 2, .flags = RATE_IN_343X },
+       { .div = 4, .val = 4, .flags = RATE_IN_343X },
+       { .div = 0 }
+};
+
+static const struct clksel div4_core_clksel[] = {
+       { .parent = &core_ck, .rates = div4_rates },
        { .parent = NULL }
 };
 
-/*
- * REVISIT: Are these in DPLL power domain or CM power domain? docs
- * may be inconsistent here?
- */
 static struct clk dpll1_fck = {
        .name           = "dpll1_fck",
        .parent         = &core_ck,
+       .prcm_mod       = MPU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL),
+       .clksel_reg     = OMAP3430_CM_CLKSEL1_PLL,
        .clksel_mask    = OMAP3430_MPU_CLK_SRC_MASK,
-       .clksel         = div2_core_clksel,
+       .clksel         = div4_core_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-/*
- * MPU clksel:
- * If DPLL1 is locked, mpu_ck derives from DPLL1; otherwise, mpu_ck
- * derives from the high-frequency bypass clock originating from DPLL3,
- * called 'dpll1_fck'
- */
-static const struct clksel mpu_clksel[] = {
-       { .parent = &dpll1_fck,     .rates = dpll_bypass_rates },
-       { .parent = &dpll1_x2m2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
 static struct clk mpu_ck = {
        .name           = "mpu_ck",
        .parent         = &dpll1_x2m2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
-       .clksel_mask    = OMAP3430_ST_MPU_CLK_MASK,
-       .clksel         = mpu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
-       .recalc         = &omap2_clksel_recalc,
+       .clkdm          = { .name = "mpu_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 /* arm_fck is divided by two when DPLL1 locked; otherwise, passthrough mpu_ck */
@@ -1066,15 +1090,19 @@ static const struct clksel arm_fck_clksel[] = {
 static struct clk arm_fck = {
        .name           = "arm_fck",
        .parent         = &mpu_ck,
+       .prcm_mod       = MPU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(MPU_MOD, OMAP3430_CM_IDLEST_PLL),
+       .clksel_reg     = OMAP3430_CM_IDLEST_PLL,
        .clksel_mask    = OMAP3430_ST_MPU_CLK_MASK,
        .clksel         = arm_fck_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "mpu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
+/* XXX What about neon_clkdm ? */
+
 /*
  * REVISIT: This clock is never specifically defined in the 3430 TRM,
  * although it is referenced - so this is a guess
@@ -1084,59 +1112,54 @@ static struct clk emu_mpu_alwon_ck = {
        .parent         = &mpu_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "mpu_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dpll2_fck = {
        .name           = "dpll2_fck",
        .parent         = &core_ck,
+       .prcm_mod       = OMAP3430_IVA2_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSEL1_PLL),
+       .clksel_reg     = OMAP3430_CM_CLKSEL1_PLL,
        .clksel_mask    = OMAP3430_IVA2_CLK_SRC_MASK,
-       .clksel         = div2_core_clksel,
+       .clksel         = div4_core_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-/*
- * IVA2 clksel:
- * If DPLL2 is locked, iva2_ck derives from DPLL2; otherwise, iva2_ck
- * derives from the high-frequency bypass clock originating from DPLL3,
- * called 'dpll2_fck'
- */
-
-static const struct clksel iva2_clksel[] = {
-       { .parent = &dpll2_fck,   .rates = dpll_bypass_rates },
-       { .parent = &dpll2_m2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
-};
-
 static struct clk iva2_ck = {
        .name           = "iva2_ck",
        .parent         = &dpll2_m2_ck,
+       .prcm_mod       = OMAP3430_IVA2_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_IVA2_MOD,
-                                         OMAP3430_CM_IDLEST_PLL),
-       .clksel_mask    = OMAP3430_ST_IVA2_CLK_MASK,
-       .clksel         = iva2_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
-       .recalc         = &omap2_clksel_recalc,
+       .clkdm          = { .name = "iva2_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 /* Common interface clocks */
 
+static const struct clksel div2_core_clksel[] = {
+       { .parent = &core_ck, .rates = div2_rates },
+       { .parent = NULL }
+};
+
 static struct clk l3_ick = {
        .name           = "l3_ick",
        .parent         = &core_ck,
+       .prcm_mod       = CORE_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_L3_MASK,
        .clksel         = div2_core_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1148,12 +1171,14 @@ static const struct clksel div2_l3_clksel[] = {
 static struct clk l4_ick = {
        .name           = "l4_ick",
        .parent         = &l3_ick,
+       .prcm_mod       = CORE_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_L4_MASK,
        .clksel         = div2_l3_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 
 };
@@ -1166,11 +1191,13 @@ static const struct clksel div2_l4_clksel[] = {
 static struct clk rm_ick = {
        .name           = "rm_ick",
        .parent         = &l4_ick,
+       .prcm_mod       = WKUP_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_RM_MASK,
        .clksel         = div2_l4_clksel,
        .flags          = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1183,43 +1210,60 @@ static const struct clksel gfx_l3_clksel[] = {
        { .parent = NULL }
 };
 
-static struct clk gfx_l3_fck = {
-       .name           = "gfx_l3_fck",
+/* Virtual parent clock for gfx_l3_ick and gfx_l3_fck */
+static struct clk gfx_l3_ck = {
+       .name           = "gfx_l3_ck",
        .parent         = &l3_ick,
+       .prcm_mod       = GFX_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP_EN_GFX_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_CLKSEL),
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "gfx_3430es1_clkdm" },
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk gfx_l3_fck = {
+       .name           = "gfx_l3_fck",
+       .parent         = &gfx_l3_ck,
+       .prcm_mod       = GFX_MOD,
+       .init           = &omap2_init_clksel_parent,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP_CLKSEL_GFX_MASK,
        .clksel         = gfx_l3_clksel,
-       .flags          = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES,
+       .flags          = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES |
+                               PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "gfx_3430es1_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gfx_l3_ick = {
        .name           = "gfx_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP_EN_GFX_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES1,
+       .parent         = &gfx_l3_ck,
+       .flags          = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "gfx_3430es1_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gfx_cg1_ck = {
        .name           = "gfx_cg1_ck",
        .parent         = &gfx_l3_fck, /* REVISIT: correct? */
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+       .prcm_mod       = GFX_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430ES1_EN_2D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "gfx_3430es1_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gfx_cg2_ck = {
        .name           = "gfx_cg2_ck",
        .parent         = &gfx_l3_fck, /* REVISIT: correct? */
-       .enable_reg     = OMAP_CM_REGADDR(GFX_MOD, CM_FCLKEN),
+       .prcm_mod       = GFX_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430ES1_EN_3D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "gfx_3430es1_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1246,21 +1290,25 @@ static const struct clksel sgx_clksel[] = {
 static struct clk sgx_fck = {
        .name           = "sgx_fck",
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_FCLKEN),
-       .enable_bit     = OMAP3430ES2_EN_SGX_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_CLKSEL),
+       .prcm_mod       = OMAP3430ES2_SGX_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430ES2_CLKSEL_SGX_MASK,
        .clksel         = sgx_clksel,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm          = { .name = "sgx_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk sgx_ick = {
        .name           = "sgx_ick",
        .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_SGX_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP3430ES2_EN_SGX_SHIFT,
+       .prcm_mod       = OMAP3430ES2_SGX_MOD,
+       .enable_reg     = CM_ICLKEN,
+       .enable_bit     = OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm          = { .name = "sgx_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1269,9 +1317,11 @@ static struct clk sgx_ick = {
 static struct clk d2d_26m_fck = {
        .name           = "d2d_26m_fck",
        .parent         = &sys_ck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430ES1_EN_D2D_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "d2d_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1284,53 +1334,67 @@ static const struct clksel omap343x_gpt_clksel[] = {
 static struct clk gpt10_fck = {
        .name           = "gpt10_fck",
        .parent         = &sys_ck,
+       .prcm_mod       = CORE_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_GPT10_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT10_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT10_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt11_fck = {
        .name           = "gpt11_fck",
        .parent         = &sys_ck,
+       .prcm_mod       = CORE_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_GPT11_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT11_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT11_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk cpefuse_fck = {
        .name           = "cpefuse_fck",
        .parent         = &sys_ck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = OMAP3430ES2_CM_FCLKEN3,
        .enable_bit     = OMAP3430ES2_EN_CPEFUSE_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_CPEFUSE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "cm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk ts_fck = {
        .name           = "ts_fck",
        .parent         = &omap_32k_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = OMAP3430ES2_CM_FCLKEN3,
        .enable_bit     = OMAP3430ES2_EN_TS_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbtll_fck = {
        .name           = "usbtll_fck",
-       .parent         = &omap_120m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, OMAP3430ES2_CM_FCLKEN3),
+       .parent         = &dpll5_m2_ck,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = OMAP3430ES2_CM_FCLKEN3,
        .enable_bit     = OMAP3430ES2_EN_USBTLL_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_USBTLL_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1341,45 +1405,57 @@ static struct clk core_96m_fck = {
        .parent         = &omap_96m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs3_fck = {
        .name           = "mmchs_fck",
-       .id             = 3,
+       .id             = 2,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_MMC3_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs2_fck = {
        .name           = "mmchs_fck",
-       .id             = 2,
+       .id             = 1,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MMC2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mspro_fck = {
        .name           = "mspro_fck",
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MSPRO_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MSPRO_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs1_fck = {
        .name           = "mmchs_fck",
-       .id             = 1,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MMC1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1387,19 +1463,25 @@ static struct clk i2c3_fck = {
        .name           = "i2c_fck",
        .id             = 3,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_I2C3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk i2c2_fck = {
        .name           = "i2c_fck",
-       .id             = 2,
+       .id             = 2,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_I2C2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1407,9 +1489,12 @@ static struct clk i2c1_fck = {
        .name           = "i2c_fck",
        .id             = 1,
        .parent         = &core_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_I2C1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1433,32 +1518,58 @@ static const struct clksel mcbsp_15_clksel[] = {
        { .parent = NULL }
 };
 
-static struct clk mcbsp5_fck = {
-       .name           = "mcbsp_fck",
+static struct clk mcbsp5_src_fck = {
+       .name           = "mcbsp_src_fck",
        .id             = 5,
+       .prcm_mod       = CLK_REG_IN_SCM,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
-       .enable_bit     = OMAP3430_EN_MCBSP5_SHIFT,
-       .clksel_reg     = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+       .clksel_reg     = OMAP343X_CONTROL_DEVCONF1,
        .clksel_mask    = OMAP2_MCBSP5_CLKS_MASK,
        .clksel         = mcbsp_15_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static struct clk mcbsp1_fck = {
+static struct clk mcbsp5_fck = {
        .name           = "mcbsp_fck",
+       .id             = 5,
+       .parent         = &mcbsp5_src_fck,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
+       .enable_bit     = OMAP3430_EN_MCBSP5_SHIFT,
+       .idlest_bit     = OMAP3430_ST_MCBSP5_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk mcbsp1_src_fck = {
+       .name           = "mcbsp_src_fck",
        .id             = 1,
+       .prcm_mod       = CLK_REG_IN_SCM,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
-       .enable_bit     = OMAP3430_EN_MCBSP1_SHIFT,
-       .clksel_reg     = OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_reg     = OMAP2_CONTROL_DEVCONF0,
        .clksel_mask    = OMAP2_MCBSP1_CLKS_MASK,
        .clksel         = mcbsp_15_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
+static struct clk mcbsp1_fck = {
+       .name           = "mcbsp_fck",
+       .id             = 1,
+       .parent         = &mcbsp1_src_fck,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
+       .enable_bit     = OMAP3430_EN_MCBSP1_SHIFT,
+       .idlest_bit     = OMAP3430_ST_MCBSP1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .recalc         = &followparent_recalc,
+};
+
 /* CORE_48M_FCK-derived clocks */
 
 static struct clk core_48m_fck = {
@@ -1466,6 +1577,7 @@ static struct clk core_48m_fck = {
        .parent         = &omap_48m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1473,9 +1585,12 @@ static struct clk mcspi4_fck = {
        .name           = "mcspi_fck",
        .id             = 4,
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1483,9 +1598,12 @@ static struct clk mcspi3_fck = {
        .name           = "mcspi_fck",
        .id             = 3,
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1493,9 +1611,12 @@ static struct clk mcspi2_fck = {
        .name           = "mcspi_fck",
        .id             = 2,
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1503,36 +1624,49 @@ static struct clk mcspi1_fck = {
        .name           = "mcspi_fck",
        .id             = 1,
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart2_fck = {
        .name           = "uart2_fck",
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_UART2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart1_fck = {
        .name           = "uart1_fck",
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_UART1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
+/* XXX doublecheck: is this idle or standby? */
 static struct clk fshostusb_fck = {
        .name           = "fshostusb_fck",
        .parent         = &core_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES1,
+       .idlest_bit     = OMAP3430ES1_ST_FSHOSTUSB_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1543,15 +1677,19 @@ static struct clk core_12m_fck = {
        .parent         = &omap_12m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk hdq_fck = {
        .name           = "hdq_fck",
        .parent         = &core_12m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_HDQ_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_HDQ_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1572,23 +1710,51 @@ static const struct clksel ssi_ssr_clksel[] = {
        { .parent = NULL }
 };
 
-static struct clk ssi_ssr_fck = {
+static struct clk ssi_ssr_fck_3430es1 = {
        .name           = "ssi_ssr_fck",
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
        .enable_bit     = OMAP3430_EN_SSI_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_SSI_MASK,
        .clksel         = ssi_ssr_clksel,
-       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .flags          = CLOCK_IN_OMAP3430ES1 | RATE_PROPAGATES,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static struct clk ssi_sst_fck = {
+static struct clk ssi_ssr_fck_3430es2 = {
+       .name           = "ssi_ssr_fck",
+       .init           = &omap2_init_clksel_parent,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_FCLKEN1,
+       .enable_bit     = OMAP3430_EN_SSI_SHIFT,
+       .idlest_bit     = OMAP3430ES2_ST_SSI_IDLE_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
+       .clksel_mask    = OMAP3430_CLKSEL_SSI_MASK,
+       .clksel         = ssi_ssr_clksel,
+       .flags          = CLOCK_IN_OMAP3430ES2 | RATE_PROPAGATES | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .recalc         = &omap2_clksel_recalc,
+};
+
+/* It's unfortunate that we need to duplicate this clock. */
+static struct clk ssi_sst_fck_3430es1 = {
        .name           = "ssi_sst_fck",
-       .parent         = &ssi_ssr_fck,
+       .parent         = &ssi_ssr_fck_3430es1,
        .fixed_div      = 2,
-       .flags          = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+       .flags          = CLOCK_IN_OMAP3430ES1 | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .recalc         = &omap2_fixed_divisor_recalc,
+};
+
+static struct clk ssi_sst_fck_3430es2 = {
+       .name           = "ssi_sst_fck",
+       .parent         = &ssi_ssr_fck_3430es2,
+       .fixed_div      = 2,
+       .flags          = CLOCK_IN_OMAP3430ES2 | PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_fixed_divisor_recalc,
 };
 
@@ -1596,29 +1762,51 @@ static struct clk ssi_sst_fck = {
 
 /* CORE_L3_ICK based clocks */
 
+/*
+ * XXX must add clk_enable/clk_disable for these if standard code won't
+ * handle it
+ */
 static struct clk core_l3_ick = {
        .name           = "core_l3_ick",
        .parent         = &l3_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk hsotgusb_ick = {
+static struct clk hsotgusb_ick_3430es1 = {
        .name           = "hsotgusb_ick",
        .parent         = &core_l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_HSOTGUSB_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "core_l3_clkdm" },
+       .recalc         = &followparent_recalc,
+};
+
+static struct clk hsotgusb_ick_3430es2 = {
+       .name           = "hsotgusb_ick",
+       .parent         = &core_l3_ick,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
+       .enable_bit     = OMAP3430_EN_HSOTGUSB_SHIFT,
+       .idlest_bit     = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk sdrc_ick = {
        .name           = "sdrc_ick",
        .parent         = &core_l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_SDRC_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
+       .idlest_bit     = OMAP3430_ST_SDRC_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | ENABLE_ON_INIT | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1627,6 +1815,7 @@ static struct clk gpmc_fck = {
        .parent         = &core_l3_ick,
        .flags          = CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK |
                                ENABLE_ON_INIT,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1637,15 +1826,19 @@ static struct clk security_l3_ick = {
        .parent         = &l3_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk pka_ick = {
        .name           = "pka_ick",
        .parent         = &security_l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP3430_EN_PKA_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_PKA_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l3_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1656,25 +1849,32 @@ static struct clk core_l4_ick = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbtll_ick = {
        .name           = "usbtll_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN3),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN3,
        .enable_bit     = OMAP3430ES2_EN_USBTLL_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_USBTLL_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs3_ick = {
        .name           = "mmchs_ick",
-       .id             = 3,
+       .id             = 2,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430ES2_EN_MMC3_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_MMC3_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1682,74 +1882,97 @@ static struct clk mmchs3_ick = {
 static struct clk icr_ick = {
        .name           = "icr_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_ICR_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_ICR_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk aes2_ick = {
        .name           = "aes2_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_AES2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_AES2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk sha12_ick = {
        .name           = "sha12_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_SHA12_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_SHA12_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk des2_ick = {
        .name           = "des2_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_DES2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_DES2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs2_ick = {
        .name           = "mmchs_ick",
-       .id             = 2,
+       .id             = 1,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MMC2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MMC2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mmchs1_ick = {
        .name           = "mmchs_ick",
-       .id             = 1,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MMC1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MMC1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mspro_ick = {
        .name           = "mspro_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MSPRO_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MSPRO_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk hdq_ick = {
        .name           = "hdq_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_HDQ_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_HDQ_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1757,9 +1980,12 @@ static struct clk mcspi4_ick = {
        .name           = "mcspi_ick",
        .id             = 4,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1767,9 +1993,12 @@ static struct clk mcspi3_ick = {
        .name           = "mcspi_ick",
        .id             = 3,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1777,9 +2006,12 @@ static struct clk mcspi2_ick = {
        .name           = "mcspi_ick",
        .id             = 2,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1787,9 +2019,12 @@ static struct clk mcspi1_ick = {
        .name           = "mcspi_ick",
        .id             = 1,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCSPI1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCSPI1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1797,9 +2032,12 @@ static struct clk i2c3_ick = {
        .name           = "i2c_ick",
        .id             = 3,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_I2C3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1807,9 +2045,12 @@ static struct clk i2c2_ick = {
        .name           = "i2c_ick",
        .id             = 2,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_I2C2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1817,45 +2058,60 @@ static struct clk i2c1_ick = {
        .name           = "i2c_ick",
        .id             = 1,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_I2C1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_I2C1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart2_ick = {
        .name           = "uart2_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_UART2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart1_ick = {
        .name           = "uart1_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_UART1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt11_ick = {
        .name           = "gpt11_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_GPT11_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT11_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt10_ick = {
        .name           = "gpt10_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_GPT10_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT10_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1863,9 +2119,12 @@ static struct clk mcbsp5_ick = {
        .name           = "mcbsp_ick",
        .id             = 5,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCBSP5_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCBSP5_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1873,36 +2132,48 @@ static struct clk mcbsp1_ick = {
        .name           = "mcbsp_ick",
        .id             = 1,
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MCBSP1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCBSP1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk fac_ick = {
        .name           = "fac_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430ES1_EN_FAC_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES1,
+       .idlest_bit     = OMAP3430ES1_ST_FAC_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk mailboxes_ick = {
        .name           = "mailboxes_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_MAILBOXES_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MAILBOXES_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk omapctrl_ick = {
        .name           = "omapctrl_ick",
        .parent         = &core_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_OMAPCTRL_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X | ENABLE_ON_INIT,
+       .idlest_bit     = OMAP3430_ST_OMAPCTRL_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | ENABLE_ON_INIT | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -1913,21 +2184,37 @@ static struct clk ssi_l4_ick = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk ssi_ick = {
+static struct clk ssi_ick_3430es1 = {
        .name           = "ssi_ick",
        .parent         = &ssi_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430_EN_SSI_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-/* REVISIT: Technically the TRM claims that this is CORE_CLK based,
- * but l4_ick makes more sense to me */
+static struct clk ssi_ick_3430es2 = {
+       .name           = "ssi_ick",
+       .parent         = &ssi_l4_ick,
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN1,
+       .enable_bit     = OMAP3430_EN_SSI_SHIFT,
+       .idlest_bit     = OMAP3430ES2_ST_SSI_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
+       .recalc         = &followparent_recalc,
+};
 
+/*
+ * REVISIT: Technically the TRM claims that this is CORE_CLK based,
+ * but l4_ick makes more sense to me
+ */
 static const struct clksel usb_l4_clksel[] = {
        { .parent = &l4_ick, .rates = div2_rates },
        { .parent = NULL },
@@ -1936,13 +2223,16 @@ static const struct clksel usb_l4_clksel[] = {
 static struct clk usb_l4_ick = {
        .name           = "usb_l4_ick",
        .parent         = &l4_ick,
+       .prcm_mod       = CORE_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1),
+       .enable_reg     = CM_ICLKEN1,
        .enable_bit     = OMAP3430ES1_EN_FSHOSTUSB_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430ES1_ST_FSHOSTUSB_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430ES1_CLKSEL_FSHOSTUSB_MASK,
        .clksel         = usb_l4_clksel,
-       .flags          = CLOCK_IN_OMAP3430ES1,
+       .flags          = CLOCK_IN_OMAP3430ES1 | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -1955,138 +2245,174 @@ static struct clk security_l4_ick2 = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk aes1_ick = {
        .name           = "aes1_ick",
        .parent         = &security_l4_ick2,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP3430_EN_AES1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_AES1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk rng_ick = {
        .name           = "rng_ick",
        .parent         = &security_l4_ick2,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP3430_EN_RNG_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_RNG_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk sha11_ick = {
        .name           = "sha11_ick",
        .parent         = &security_l4_ick2,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP3430_EN_SHA11_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_SHA11_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk des1_ick = {
        .name           = "des1_ick",
        .parent         = &security_l4_ick2,
-       .enable_reg     = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2),
+       .prcm_mod       = CORE_MOD,
+       .enable_reg     = CM_ICLKEN2,
        .enable_bit     = OMAP3430_EN_DES1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_DES1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 /* DSS */
-static const struct clksel dss1_alwon_fck_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll4_m4x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
+static struct clk dss1_alwon_fck_3430es1 = {
+       .name           = "dss1_alwon_fck",
+       .parent         = &dpll4_m4x2_ck,
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430_EN_DSS1_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "dss_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
-static struct clk dss1_alwon_fck = {
+static struct clk dss1_alwon_fck_3430es2 = {
        .name           = "dss1_alwon_fck",
        .parent         = &dpll4_m4x2_ck,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_DSS1_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
-       .clksel         = dss1_alwon_fck_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
-       .recalc         = &omap2_clksel_recalc,
+       .idlest_bit     = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "dss_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
 static struct clk dss_tv_fck = {
        .name           = "dss_tv_fck",
        .parent         = &omap_54m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_TV_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "dss_clkdm" }, /* XXX: in cm_clkdm? */
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dss_96m_fck = {
        .name           = "dss_96m_fck",
        .parent         = &omap_96m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_TV_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "dss_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk dss2_alwon_fck = {
        .name           = "dss2_alwon_fck",
        .parent         = &sys_ck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_DSS2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "dss_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk dss_ick = {
+static struct clk dss_ick_3430es1 = {
        /* Handles both L3 and L4 clocks */
        .name           = "dss_ick",
        .parent         = &l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_DSS_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP3430ES1,
+       .clkdm          = { .name = "dss_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-/* CAM */
-
-static const struct clksel cam_mclk_clksel[] = {
-       { .parent = &sys_ck,        .rates = dpll_bypass_rates },
-       { .parent = &dpll4_m5x2_ck, .rates = dpll_locked_rates },
-       { .parent = NULL }
+static struct clk dss_ick_3430es2 = {
+       /* Handles both L3 and L4 clocks */
+       .name           = "dss_ick",
+       .parent         = &l4_ick,
+       .prcm_mod       = OMAP3430_DSS_MOD,
+       .enable_reg     = CM_ICLKEN,
+       .enable_bit     = OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT,
+       .idlest_bit     = OMAP3430ES2_ST_DSS_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "dss_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
+/* CAM */
+
 static struct clk cam_mclk = {
        .name           = "cam_mclk",
        .parent         = &dpll4_m5x2_ck,
-       .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST),
-       .clksel_mask    = OMAP3430_ST_PERIPH_CLK_MASK,
-       .clksel         = cam_mclk_clksel,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_CAM_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_CAM_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
-       .recalc         = &omap2_clksel_recalc,
+       .clkdm          = { .name = "cam_clkdm" },
+       .recalc         = &followparent_recalc,
 };
 
-static struct clk cam_l3_ick = {
-       .name           = "cam_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
+static struct clk cam_ick = {
+       /* Handles both L3 and L4 clocks */
+       .name           = "cam_ick",
+       .parent         = &l4_ick,
+       .prcm_mod       = OMAP3430_CAM_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_CAM_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "cam_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk cam_l4_ick = {
-       .name           = "cam_l4_ick",
-       .parent         = &l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_CAM_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP3430_EN_CAM_SHIFT,
+static struct clk csi2_96m_fck = {
+       .name           = "csi2_96m_fck",
+       .parent         = &core_96m_fck,
+       .prcm_mod       = OMAP3430_CAM_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430_EN_CSI2_SHIFT,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "cam_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2094,46 +2420,37 @@ static struct clk cam_l4_ick = {
 
 static struct clk usbhost_120m_fck = {
        .name           = "usbhost_120m_fck",
-       .parent         = &omap_120m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
+       .parent         = &dpll5_m2_ck,
+       .prcm_mod       = OMAP3430ES2_USBHOST_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430ES2_EN_USBHOST2_SHIFT,
        .flags          = CLOCK_IN_OMAP3430ES2,
+       .clkdm          = { .name = "usbhost_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk usbhost_48m_fck = {
        .name           = "usbhost_48m_fck",
        .parent         = &omap_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430ES2_USBHOST_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430ES2_EN_USBHOST1_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
-       .recalc         = &followparent_recalc,
-};
-
-static struct clk usbhost_l3_ick = {
-       .name           = "usbhost_l3_ick",
-       .parent         = &l3_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
-       .enable_bit     = OMAP3430ES2_EN_USBHOST_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "usbhost_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk usbhost_l4_ick = {
-       .name           = "usbhost_l4_ick",
+static struct clk usbhost_ick = {
+       /* Handles both L3 and L4 clocks */
+       .name           = "usbhost_ick",
        .parent         = &l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430ES2_USBHOST_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430ES2_EN_USBHOST_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
-       .recalc         = &followparent_recalc,
-};
-
-static struct clk usbhost_sar_fck = {
-       .name           = "usbhost_sar_fck",
-       .parent         = &osc_sys_ck,
-       .enable_reg     = OMAP_PRM_REGADDR(OMAP3430ES2_USBHOST_MOD, PM_PWSTCTRL),
-       .enable_bit     = OMAP3430ES2_SAVEANDRESTORE_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_USBHOST_IDLE_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "usbhost_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2157,7 +2474,7 @@ static const struct clksel_rate usim_120m_rates[] = {
 
 static const struct clksel usim_clksel[] = {
        { .parent = &omap_96m_fck,      .rates = usim_96m_rates },
-       { .parent = &omap_120m_fck,     .rates = usim_120m_rates },
+       { .parent = &dpll5_m2_ck,       .rates = usim_120m_rates },
        { .parent = &sys_ck,            .rates = div2_rates },
        { .parent = NULL },
 };
@@ -2165,25 +2482,32 @@ static const struct clksel usim_clksel[] = {
 /* 3430ES2 only */
 static struct clk usim_fck = {
        .name           = "usim_fck",
+       .prcm_mod       = WKUP_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430ES2_EN_USIMOCP_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430ES2_ST_USIMOCP_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430ES2_CLKSEL_USIMOCP_MASK,
        .clksel         = usim_clksel,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
+/* XXX should gpt1's clksel have wkup_32k_fck as the 32k opt? */
 static struct clk gpt1_fck = {
        .name           = "gpt1_fck",
+       .prcm_mod       = WKUP_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT1_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT1_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT1_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2191,24 +2515,31 @@ static struct clk wkup_32k_fck = {
        .name           = "wkup_32k_fck",
        .parent         = &omap_32k_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio1_fck = {
-       .name           = "gpio1_fck",
+static struct clk gpio1_dbck = {
+       .name           = "gpio1_dbck",
        .parent         = &wkup_32k_fck,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt2_fck = {
        .name           = "wdt2_fck",
        .parent         = &wkup_32k_fck,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_WDT2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_WDT2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2216,71 +2547,91 @@ static struct clk wkup_l4_ick = {
        .name           = "wkup_l4_ick",
        .parent         = &sys_ck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-/* 3430ES2 only */
-/* Never specifically named in the TRM, so we have to infer a likely name */
 static struct clk usim_ick = {
        .name           = "usim_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430ES2_EN_USIMOCP_SHIFT,
-       .flags          = CLOCK_IN_OMAP3430ES2,
+       .idlest_bit     = OMAP3430ES2_ST_USIMOCP_SHIFT,
+       .flags          = CLOCK_IN_OMAP3430ES2 | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt2_ick = {
        .name           = "wdt2_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_WDT2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_WDT2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt1_ick = {
        .name           = "wdt1_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_WDT1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_WDT1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio1_ick = {
        .name           = "gpio1_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk omap_32ksync_ick = {
        .name           = "omap_32ksync_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_32KSYNC_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_32KSYNC_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt12_ick = {
        .name           = "gpt12_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT12_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT12_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt1_ick = {
        .name           = "gpt1_ick",
        .parent         = &wkup_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_ICLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2293,6 +2644,7 @@ static struct clk per_96m_fck = {
        .parent         = &omap_96m_alwon_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2301,172 +2653,219 @@ static struct clk per_48m_fck = {
        .parent         = &omap_48m_fck,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart3_fck = {
        .name           = "uart3_fck",
        .parent         = &per_48m_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_UART3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt2_fck = {
        .name           = "gpt2_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT2_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT2_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT2_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt3_fck = {
        .name           = "gpt3_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT3_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT3_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT3_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt4_fck = {
        .name           = "gpt4_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT4_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT4_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT4_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt5_fck = {
        .name           = "gpt5_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT5_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT5_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT5_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt6_fck = {
        .name           = "gpt6_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT6_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT6_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT6_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt7_fck = {
        .name           = "gpt7_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT7_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT7_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT7_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt8_fck = {
        .name           = "gpt8_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT8_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT8_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT8_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk gpt9_fck = {
        .name           = "gpt9_fck",
+       .prcm_mod       = OMAP3430_PER_MOD,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPT9_SHIFT,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_CLKSEL),
+       .idlest_bit     = OMAP3430_ST_GPT9_SHIFT,
+       .clksel_reg     = CM_CLKSEL,
        .clksel_mask    = OMAP3430_CLKSEL_GPT9_MASK,
        .clksel         = omap343x_gpt_clksel,
-       .flags          = CLOCK_IN_OMAP343X,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk per_32k_alwon_fck = {
        .name           = "per_32k_alwon_fck",
        .parent         = &omap_32k_fck,
+       .clkdm          = { .name = "per_clkdm" },
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio6_fck = {
-       .name           = "gpio6_fck",
+static struct clk gpio6_dbck = {
+       .name           = "gpio6_dbck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO6_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO6_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio5_fck = {
-       .name           = "gpio5_fck",
+static struct clk gpio5_dbck = {
+       .name           = "gpio5_dbck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO5_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO5_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio4_fck = {
-       .name           = "gpio4_fck",
+static struct clk gpio4_dbck = {
+       .name           = "gpio4_dbck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio3_fck = {
-       .name           = "gpio3_fck",
+static struct clk gpio3_dbck = {
+       .name           = "gpio3_dbck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
-static struct clk gpio2_fck = {
-       .name           = "gpio2_fck",
+static struct clk gpio2_dbck = {
+       .name           = "gpio2_dbck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_GPIO2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt3_fck = {
        .name           = "wdt3_fck",
        .parent         = &per_32k_alwon_fck,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_WDT3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_WDT3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2475,141 +2874,187 @@ static struct clk per_l4_ick = {
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES |
                                PARENT_CONTROLS_CLOCK,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio6_ick = {
        .name           = "gpio6_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO6_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO6_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio5_ick = {
        .name           = "gpio5_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO5_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO5_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio4_ick = {
        .name           = "gpio4_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio3_ick = {
        .name           = "gpio3_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpio2_ick = {
        .name           = "gpio2_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPIO2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPIO2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk wdt3_ick = {
        .name           = "wdt3_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_WDT3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_WDT3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk uart3_ick = {
        .name           = "uart3_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_UART3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_UART3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt9_ick = {
        .name           = "gpt9_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT9_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT9_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt8_ick = {
        .name           = "gpt8_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT8_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT8_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt7_ick = {
        .name           = "gpt7_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT7_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT7_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt6_ick = {
        .name           = "gpt6_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT6_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT6_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt5_ick = {
        .name           = "gpt5_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT5_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT5_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt4_ick = {
        .name           = "gpt4_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt3_ick = {
        .name           = "gpt3_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static struct clk gpt2_ick = {
        .name           = "gpt2_ick",
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_GPT2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_GPT2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2617,9 +3062,12 @@ static struct clk mcbsp2_ick = {
        .name           = "mcbsp_ick",
        .id             = 2,
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_MCBSP2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCBSP2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2627,9 +3075,12 @@ static struct clk mcbsp3_ick = {
        .name           = "mcbsp_ick",
        .id             = 3,
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_MCBSP3_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCBSP3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2637,54 +3088,96 @@ static struct clk mcbsp4_ick = {
        .name           = "mcbsp_ick",
        .id             = 4,
        .parent         = &per_l4_ick,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_ICLKEN,
        .enable_bit     = OMAP3430_EN_MCBSP4_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X,
+       .idlest_bit     = OMAP3430_ST_MCBSP4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 static const struct clksel mcbsp_234_clksel[] = {
-       { .parent = &per_96m_fck, .rates = common_mcbsp_96m_rates },
+       { .parent = &core_96m_fck, .rates = common_mcbsp_96m_rates },
        { .parent = &mcbsp_clks,   .rates = common_mcbsp_mcbsp_rates },
        { .parent = NULL }
 };
 
-static struct clk mcbsp2_fck = {
-       .name           = "mcbsp_fck",
+static struct clk mcbsp2_src_fck = {
+       .name           = "mcbsp_src_fck",
        .id             = 2,
+       .prcm_mod       = CLK_REG_IN_SCM,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
-       .enable_bit     = OMAP3430_EN_MCBSP2_SHIFT,
-       .clksel_reg     = OMAP343X_CTRL_REGADDR(OMAP2_CONTROL_DEVCONF0),
+       .clksel_reg     = OMAP2_CONTROL_DEVCONF0,
        .clksel_mask    = OMAP2_MCBSP2_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static struct clk mcbsp3_fck = {
+static struct clk mcbsp2_fck = {
        .name           = "mcbsp_fck",
+       .id             = 2,
+       .parent         = &mcbsp2_src_fck,
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430_EN_MCBSP2_SHIFT,
+       .idlest_bit     = OMAP3430_ST_MCBSP2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
+       .recalc         = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp3_src_fck = {
+       .name           = "mcbsp_src_fck",
        .id             = 3,
+       .prcm_mod       = CLK_REG_IN_SCM,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
-       .enable_bit     = OMAP3430_EN_MCBSP3_SHIFT,
-       .clksel_reg     = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+       .clksel_reg     = OMAP343X_CONTROL_DEVCONF1,
        .clksel_mask    = OMAP2_MCBSP3_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
-static struct clk mcbsp4_fck = {
+static struct clk mcbsp3_fck = {
        .name           = "mcbsp_fck",
+       .id             = 3,
+       .parent         = &mcbsp3_src_fck,
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430_EN_MCBSP3_SHIFT,
+       .idlest_bit     = OMAP3430_ST_MCBSP3_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
+       .recalc         = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp4_src_fck = {
+       .name           = "mcbsp_src_fck",
        .id             = 4,
+       .prcm_mod       = CLK_REG_IN_SCM,
        .init           = &omap2_init_clksel_parent,
-       .enable_reg     = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
-       .enable_bit     = OMAP3430_EN_MCBSP4_SHIFT,
-       .clksel_reg     = OMAP343X_CTRL_REGADDR(OMAP343X_CONTROL_DEVCONF1),
+       .clksel_reg     = OMAP343X_CONTROL_DEVCONF1,
        .clksel_mask    = OMAP2_MCBSP4_CLKS_MASK,
        .clksel         = mcbsp_234_clksel,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "per_clkdm" },
+       .recalc         = &omap2_clksel_recalc,
+};
+
+static struct clk mcbsp4_fck = {
+       .name           = "mcbsp_fck",
+       .id             = 4,
+       .parent         = &mcbsp4_src_fck,
+       .prcm_mod       = OMAP3430_PER_MOD,
+       .enable_reg     = CM_FCLKEN,
+       .enable_bit     = OMAP3430_EN_MCBSP4_SHIFT,
+       .idlest_bit     = OMAP3430_ST_MCBSP4_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | WAIT_READY,
+       .clkdm          = { .name = "per_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2727,11 +3220,13 @@ static const struct clksel emu_src_clksel[] = {
  */
 static struct clk emu_src_ck = {
        .name           = "emu_src_ck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_MUX_CTRL_MASK,
        .clksel         = emu_src_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2750,11 +3245,13 @@ static const struct clksel pclk_emu_clksel[] = {
 
 static struct clk pclk_fck = {
        .name           = "pclk_fck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_CLKSEL_PCLK_MASK,
        .clksel         = pclk_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2772,11 +3269,13 @@ static const struct clksel pclkx2_emu_clksel[] = {
 
 static struct clk pclkx2_fck = {
        .name           = "pclkx2_fck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_CLKSEL_PCLKX2_MASK,
        .clksel         = pclkx2_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2787,21 +3286,25 @@ static const struct clksel atclk_emu_clksel[] = {
 
 static struct clk atclk_fck = {
        .name           = "atclk_fck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_CLKSEL_ATCLK_MASK,
        .clksel         = atclk_emu_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
 static struct clk traceclk_src_fck = {
        .name           = "traceclk_src_fck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_TRACE_MUX_CTRL_MASK,
        .clksel         = emu_src_clksel,
        .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2819,11 +3322,13 @@ static const struct clksel traceclk_clksel[] = {
 
 static struct clk traceclk_fck = {
        .name           = "traceclk_fck",
+       .prcm_mod       = OMAP3430_EMU_MOD,
        .init           = &omap2_init_clksel_parent,
-       .clksel_reg     = OMAP_CM_REGADDR(OMAP3430_EMU_MOD, CM_CLKSEL1),
+       .clksel_reg     = CM_CLKSEL1,
        .clksel_mask    = OMAP3430_CLKSEL_TRACECLK_MASK,
        .clksel         = traceclk_clksel,
        .flags          = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+       .clkdm          = { .name = "emu_clkdm" },
        .recalc         = &omap2_clksel_recalc,
 };
 
@@ -2833,9 +3338,12 @@ static struct clk traceclk_fck = {
 static struct clk sr1_fck = {
        .name           = "sr1_fck",
        .parent         = &sys_ck,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_SR1_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .idlest_bit     = OMAP3430_ST_SR1_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2843,9 +3351,12 @@ static struct clk sr1_fck = {
 static struct clk sr2_fck = {
        .name           = "sr2_fck",
        .parent         = &sys_ck,
-       .enable_reg     = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN),
+       .prcm_mod       = WKUP_MOD,
+       .enable_reg     = CM_FCLKEN,
        .enable_bit     = OMAP3430_EN_SR2_SHIFT,
-       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES,
+       .idlest_bit     = OMAP3430_ST_SR2_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | RATE_PROPAGATES | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2853,15 +3364,19 @@ static struct clk sr_l4_ick = {
        .name           = "sr_l4_ick",
        .parent         = &l4_ick,
        .flags          = CLOCK_IN_OMAP343X,
+       .clkdm          = { .name = "core_l4_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
 /* SECURE_32K_FCK clocks */
 
+/* XXX Make sure idlest_bit/wait_ready with no enable_bit works */
 static struct clk gpt12_fck = {
        .name           = "gpt12_fck",
        .parent         = &secure_32k_fck,
-       .flags          = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+       .idlest_bit     = OMAP3430_ST_GPT12_SHIFT,
+       .flags          = CLOCK_IN_OMAP343X | ALWAYS_ENABLED | WAIT_READY,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2869,6 +3384,7 @@ static struct clk wdt1_fck = {
        .name           = "wdt1_fck",
        .parent         = &secure_32k_fck,
        .flags          = CLOCK_IN_OMAP343X | ALWAYS_ENABLED,
+       .clkdm          = { .name = "prm_clkdm" },
        .recalc         = &followparent_recalc,
 };
 
@@ -2903,7 +3419,6 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &omap_96m_alwon_fck,
        &omap_96m_fck,
        &cm_96m_fck,
-       &virt_omap_54m_fck,
        &omap_54m_fck,
        &omap_48m_fck,
        &omap_12m_fck,
@@ -2920,7 +3435,6 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &emu_per_alwon_ck,
        &dpll5_ck,
        &dpll5_m2_ck,
-       &omap_120m_fck,
        &clkout2_src_ck,
        &sys_clkout2,
        &corex2_fck,
@@ -2933,6 +3447,7 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &l3_ick,
        &l4_ick,
        &rm_ick,
+       &gfx_l3_ck,
        &gfx_l3_fck,
        &gfx_l3_ick,
        &gfx_cg1_ck,
@@ -2953,7 +3468,9 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &i2c3_fck,
        &i2c2_fck,
        &i2c1_fck,
+       &mcbsp5_src_fck,
        &mcbsp5_fck,
+       &mcbsp1_src_fck,
        &mcbsp1_fck,
        &core_48m_fck,
        &mcspi4_fck,
@@ -2965,10 +3482,13 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &fshostusb_fck,
        &core_12m_fck,
        &hdq_fck,
-       &ssi_ssr_fck,
-       &ssi_sst_fck,
+       &ssi_ssr_fck_3430es1,
+       &ssi_ssr_fck_3430es2,
+       &ssi_sst_fck_3430es1,
+       &ssi_sst_fck_3430es2,
        &core_l3_ick,
-       &hsotgusb_ick,
+       &hsotgusb_ick_3430es1,
+       &hsotgusb_ick_3430es2,
        &sdrc_ick,
        &gpmc_fck,
        &security_l3_ick,
@@ -3001,30 +3521,31 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &mailboxes_ick,
        &omapctrl_ick,
        &ssi_l4_ick,
-       &ssi_ick,
+       &ssi_ick_3430es1,
+       &ssi_ick_3430es2,
        &usb_l4_ick,
        &security_l4_ick2,
        &aes1_ick,
        &rng_ick,
        &sha11_ick,
        &des1_ick,
-       &dss1_alwon_fck,
+       &dss1_alwon_fck_3430es1,
+       &dss1_alwon_fck_3430es2,
        &dss_tv_fck,
        &dss_96m_fck,
        &dss2_alwon_fck,
-       &dss_ick,
+       &dss_ick_3430es1,
+       &dss_ick_3430es2,
        &cam_mclk,
-       &cam_l3_ick,
-       &cam_l4_ick,
+       &cam_ick,
+       &csi2_96m_fck,
        &usbhost_120m_fck,
        &usbhost_48m_fck,
-       &usbhost_l3_ick,
-       &usbhost_l4_ick,
-       &usbhost_sar_fck,
+       &usbhost_ick,
        &usim_fck,
        &gpt1_fck,
        &wkup_32k_fck,
-       &gpio1_fck,
+       &gpio1_dbck,
        &wdt2_fck,
        &wkup_l4_ick,
        &usim_ick,
@@ -3046,11 +3567,11 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &gpt8_fck,
        &gpt9_fck,
        &per_32k_alwon_fck,
-       &gpio6_fck,
-       &gpio5_fck,
-       &gpio4_fck,
-       &gpio3_fck,
-       &gpio2_fck,
+       &gpio6_dbck,
+       &gpio5_dbck,
+       &gpio4_dbck,
+       &gpio3_dbck,
+       &gpio2_dbck,
        &wdt3_fck,
        &per_l4_ick,
        &gpio6_ick,
@@ -3071,8 +3592,11 @@ static struct clk *onchip_34xx_clks[] __initdata = {
        &mcbsp2_ick,
        &mcbsp3_ick,
        &mcbsp4_ick,
+       &mcbsp2_src_fck,
        &mcbsp2_fck,
+       &mcbsp3_src_fck,
        &mcbsp3_fck,
+       &mcbsp4_src_fck,
        &mcbsp4_fck,
        &emu_src_ck,
        &pclk_fck,
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
new file mode 100644 (file)
index 0000000..fa62f14
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley and Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifdef CONFIG_OMAP_DEBUG_CLOCKDOMAIN
+#  define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/limits.h>
+
+#include <linux/io.h>
+
+#include <linux/bitops.h>
+
+#include <mach/clock.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+/* clkdm_list contains all registered struct clockdomains */
+static LIST_HEAD(clkdm_list);
+
+/* clkdm_mutex protects clkdm_list add and del ops */
+static DEFINE_MUTEX(clkdm_mutex);
+
+/* array of powerdomain deps to be added/removed when clkdm in hwsup mode */
+static struct clkdm_pwrdm_autodep *autodeps;
+
+
+/* Private functions */
+
+/*
+ * _autodep_lookup - resolve autodep pwrdm names to pwrdm pointers; store
+ * @autodep: struct clkdm_pwrdm_autodep * to resolve
+ *
+ * Resolve autodep powerdomain names to powerdomain pointers via
+ * pwrdm_lookup() and store the pointers in the autodep structure.  An
+ * "autodep" is a powerdomain sleep/wakeup dependency that is
+ * automatically added and removed whenever clocks in the associated
+ * clockdomain are enabled or disabled (respectively) when the
+ * clockdomain is in hardware-supervised mode. Meant to be called
+ * once at clockdomain layer initialization, since these should remain
+ * fixed for a particular architecture.  No return value.
+ */
+static void _autodep_lookup(struct clkdm_pwrdm_autodep *autodep)
+{
+       struct powerdomain *pwrdm;
+
+       if (!autodep)
+               return;
+
+       if (!omap_chip_is(autodep->omap_chip))
+               return;
+
+       pwrdm = pwrdm_lookup(autodep->pwrdm.name);
+       if (!pwrdm) {
+               pr_debug("clockdomain: _autodep_lookup: powerdomain %s "
+                        "does not exist\n", autodep->pwrdm.name);
+               WARN_ON(1);
+               return;
+       }
+       autodep->pwrdm.ptr = pwrdm;
+
+       return;
+}
+
+/*
+ * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
+ * @clkdm: struct clockdomain *
+ *
+ * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
+ * in hardware-supervised mode.  Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is enabled. No return value.
+ */
+static void _clkdm_add_autodeps(struct clockdomain *clkdm)
+{
+       struct clkdm_pwrdm_autodep *autodep;
+
+       for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
+               if (!omap_chip_is(autodep->omap_chip))
+                       continue;
+
+               pr_debug("clockdomain: adding %s sleepdep/wkdep for "
+                        "pwrdm %s\n", autodep->pwrdm.ptr->name,
+                        clkdm->pwrdm.ptr->name);
+
+               pwrdm_add_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+               pwrdm_add_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+       }
+}
+
+/*
+ * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
+ * in hardware-supervised mode.  Meant to be called from clock framework
+ * when a clock inside clockdomain 'clkdm' is disabled.  No return value.
+ */
+static void _clkdm_del_autodeps(struct clockdomain *clkdm)
+{
+       struct clkdm_pwrdm_autodep *autodep;
+
+       for (autodep = autodeps; autodep->pwrdm.ptr; autodep++) {
+               if (!omap_chip_is(autodep->omap_chip))
+                       continue;
+
+               pr_debug("clockdomain: removing %s sleepdep/wkdep for "
+                        "pwrdm %s\n", autodep->pwrdm.ptr->name,
+                        clkdm->pwrdm.ptr->name);
+
+               pwrdm_del_sleepdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+               pwrdm_del_wkdep(clkdm->pwrdm.ptr, autodep->pwrdm.ptr);
+       }
+}
+
+
+static struct clockdomain *_clkdm_lookup(const char *name)
+{
+       struct clockdomain *clkdm, *temp_clkdm;
+
+       if (!name)
+               return NULL;
+
+       clkdm = NULL;
+
+       list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+               if (!strcmp(name, temp_clkdm->name)) {
+                       clkdm = temp_clkdm;
+                       break;
+               }
+       }
+
+       return clkdm;
+}
+
+
+/* Public functions */
+
+/**
+ * clkdm_init - set up the clockdomain layer
+ * @clkdms: optional pointer to an array of clockdomains to register
+ * @init_autodeps: optional pointer to an array of autodeps to register
+ *
+ * Set up internal state.  If a pointer to an array of clockdomains
+ * was supplied, loop through the list of clockdomains, register all
+ * that are available on the current platform. Similarly, if a
+ * pointer to an array of clockdomain-powerdomain autodependencies was
+ * provided, register those.  No return value.
+ */
+void clkdm_init(struct clockdomain **clkdms,
+               struct clkdm_pwrdm_autodep *init_autodeps)
+{
+       struct clockdomain **c = NULL;
+       struct clkdm_pwrdm_autodep *autodep = NULL;
+
+       if (clkdms)
+               for (c = clkdms; *c; c++)
+                       clkdm_register(*c);
+
+       autodeps = init_autodeps;
+       if (autodeps)
+               for (autodep = autodeps; autodep->pwrdm.ptr; autodep++)
+                       _autodep_lookup(autodep);
+}
+
+/**
+ * clkdm_register - register a clockdomain
+ * @clkdm: struct clockdomain * to register
+ *
+ * Adds a clockdomain to the internal clockdomain list.
+ * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int clkdm_register(struct clockdomain *clkdm)
+{
+       int ret = -EINVAL;
+       struct powerdomain *pwrdm;
+
+       if (!clkdm || !clkdm->name)
+               return -EINVAL;
+
+       if (!omap_chip_is(clkdm->omap_chip))
+               return -EINVAL;
+
+       pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
+       if (!pwrdm) {
+               pr_debug("clockdomain: clkdm_register %s: powerdomain %s "
+                        "does not exist\n", clkdm->name, clkdm->pwrdm.name);
+               return -EINVAL;
+       }
+       clkdm->pwrdm.ptr = pwrdm;
+
+       mutex_lock(&clkdm_mutex);
+       /* Verify that the clockdomain is not already registered */
+       if (_clkdm_lookup(clkdm->name)) {
+               ret = -EEXIST;
+               goto cr_unlock;
+       };
+
+       list_add(&clkdm->node, &clkdm_list);
+
+       pwrdm_add_clkdm(pwrdm, clkdm);
+
+       pr_debug("clockdomain: registered %s\n", clkdm->name);
+       ret = 0;
+
+cr_unlock:
+       mutex_unlock(&clkdm_mutex);
+
+       return ret;
+}
+
+/**
+ * clkdm_unregister - unregister a clockdomain
+ * @clkdm: struct clockdomain * to unregister
+ *
+ * Removes a clockdomain from the internal clockdomain list.  Returns
+ * -EINVAL if clkdm argument is NULL.
+ */
+int clkdm_unregister(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       pwrdm_del_clkdm(clkdm->pwrdm.ptr, clkdm);
+
+       mutex_lock(&clkdm_mutex);
+       list_del(&clkdm->node);
+       mutex_unlock(&clkdm_mutex);
+
+       pr_debug("clockdomain: unregistered %s\n", clkdm->name);
+
+       return 0;
+}
+
+/**
+ * clkdm_lookup - look up a clockdomain by name, return a pointer
+ * @name: name of clockdomain
+ *
+ * Find a registered clockdomain by its name.  Returns a pointer to the
+ * struct clockdomain if found, or NULL otherwise.
+ */
+struct clockdomain *clkdm_lookup(const char *name)
+{
+       struct clockdomain *clkdm, *temp_clkdm;
+
+       if (!name)
+               return NULL;
+
+       clkdm = NULL;
+
+       mutex_lock(&clkdm_mutex);
+       list_for_each_entry(temp_clkdm, &clkdm_list, node) {
+               if (!strcmp(name, temp_clkdm->name)) {
+                       clkdm = temp_clkdm;
+                       break;
+               }
+       }
+       mutex_unlock(&clkdm_mutex);
+
+       return clkdm;
+}
+
+/**
+ * clkdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered clockdomain.
+ * The callback function can return anything but 0 to bail
+ * out early from the iterator.  The callback function is called with
+ * the clkdm_mutex held, so no clockdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * clockdomain control functions are fine.  Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function pointer
+ * is null.
+ */
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm))
+{
+       struct clockdomain *clkdm;
+       int ret = 0;
+
+       if (!fn)
+               return -EINVAL;
+
+       mutex_lock(&clkdm_mutex);
+       list_for_each_entry(clkdm, &clkdm_list, node) {
+               ret = (*fn)(clkdm);
+               if (ret)
+                       break;
+       }
+       mutex_unlock(&clkdm_mutex);
+
+       return ret;
+}
+
+
+/**
+ * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
+ * @clkdm: struct clockdomain *
+ *
+ * Return a pointer to the struct powerdomain that the specified clockdomain
+ * 'clkdm' exists in, or returns NULL if clkdm argument is NULL.
+ */
+struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return NULL;
+
+       return clkdm->pwrdm.ptr;
+}
+
+
+/* Hardware clockdomain control */
+
+/**
+ * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
+ * @clk: struct clk * of a clockdomain
+ *
+ * Return the clockdomain's current state transition mode from the
+ * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if clk
+ * is NULL or the current mode upon success.
+ */
+static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return -EINVAL;
+
+       v = cm_read_mod_reg(clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+       v &= clkdm->clktrctrl_mask;
+       v >>= __ffs(clkdm->clktrctrl_mask);
+
+       return v;
+}
+
+/**
+ * omap2_clkdm_sleep - force clockdomain sleep transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a sleep transition on the specified
+ * clockdomain 'clkdm'.  Returns -EINVAL if clk is NULL or if
+ * clockdomain does not support software-initiated sleep; 0 upon
+ * success.
+ */
+int omap2_clkdm_sleep(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
+               pr_debug("clockdomain: %s does not support forcing "
+                        "sleep via software\n", clkdm->name);
+               return -EINVAL;
+       }
+
+       pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
+
+       if (cpu_is_omap24xx()) {
+
+               cm_set_mod_reg_bits(OMAP24XX_FORCESTATE,
+                                   clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
+
+       } else if (cpu_is_omap34xx()) {
+
+               u32 v = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
+                        __ffs(clkdm->clktrctrl_mask));
+
+               cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+                                   clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+
+       } else {
+               BUG();
+       };
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_wakeup - force clockdomain wakeup transition
+ * @clkdm: struct clockdomain *
+ *
+ * Instruct the CM to force a wakeup transition on the specified
+ * clockdomain 'clkdm'.  Returns -EINVAL if clkdm is NULL or if the
+ * clockdomain does not support software-controlled wakeup; 0 upon
+ * success.
+ */
+int omap2_clkdm_wakeup(struct clockdomain *clkdm)
+{
+       if (!clkdm)
+               return -EINVAL;
+
+       if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
+               pr_debug("clockdomain: %s does not support forcing "
+                        "wakeup via software\n", clkdm->name);
+               return -EINVAL;
+       }
+
+       pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
+
+       if (cpu_is_omap24xx()) {
+
+               cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE,
+                                     clkdm->pwrdm.ptr->prcm_offs, PM_PWSTCTRL);
+
+       } else if (cpu_is_omap34xx()) {
+
+               u32 v = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
+                        __ffs(clkdm->clktrctrl_mask));
+
+               cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask, v,
+                                   clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+
+       } else {
+               BUG();
+       };
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Allow the hardware to automatically switch the clockdomain into
+ * active or idle states, as needed by downstream clocks.  If the
+ * clockdomain has any downstream clocks enabled in the clock
+ * framework, wkdep/sleepdep autodependencies are added; this is so
+ * device drivers can read and write to the device.  No return value.
+ */
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return;
+
+       if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
+               pr_debug("clock: automatic idle transitions cannot be enabled "
+                        "on clockdomain %s\n", clkdm->name);
+               return;
+       }
+
+       pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
+                clkdm->name);
+
+       if (atomic_read(&clkdm->usecount) > 0)
+               _clkdm_add_autodeps(clkdm);
+
+       if (cpu_is_omap24xx())
+               v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+       else if (cpu_is_omap34xx())
+               v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+       else
+               BUG();
+
+
+       cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+                           v << __ffs(clkdm->clktrctrl_mask),
+                           clkdm->pwrdm.ptr->prcm_offs,
+                           CM_CLKSTCTRL);
+}
+
+/**
+ * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
+ * @clkdm: struct clockdomain *
+ *
+ * Prevent the hardware from automatically switching the clockdomain
+ * into inactive or idle states.  If the clockdomain has downstream
+ * clocks enabled in the clock framework, wkdep/sleepdep
+ * autodependencies are removed.  No return value.
+ */
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
+{
+       u32 v;
+
+       if (!clkdm)
+               return;
+
+       if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
+               pr_debug("clockdomain: automatic idle transitions cannot be "
+                        "disabled on %s\n", clkdm->name);
+               return;
+       }
+
+       pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
+                clkdm->name);
+
+       if (cpu_is_omap24xx())
+               v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+       else if (cpu_is_omap34xx())
+               v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+       else
+               BUG();
+
+       cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+                           v << __ffs(clkdm->clktrctrl_mask),
+                           clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+
+       if (atomic_read(&clkdm->usecount) > 0)
+               _clkdm_del_autodeps(clkdm);
+}
+
+
+/* Clockdomain-to-clock framework interface code */
+
+/**
+ * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the enabled downstream clock
+ *
+ * Increment the usecount of this clockdomain 'clkdm' and ensure that
+ * it is awake.  Intended to be called by clk_enable() code.  If the
+ * clockdomain is in software-supervised idle mode, force the
+ * clockdomain to wake.  If the clockdomain is in hardware-supervised
+ * idle mode, add clkdm-pwrdm autodependencies, to ensure that devices
+ * in the clockdomain can be read from/written to by on-chip processors.
+ * Returns -EINVAL if passed null pointers; returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
+{
+       int v;
+
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream clocks for debugging purposes?
+        */
+
+       if (!clkdm || !clk)
+               return -EINVAL;
+
+       if (atomic_inc_return(&clkdm->usecount) > 1)
+               return 0;
+
+       /* Clockdomain now has one enabled downstream clock */
+
+       pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
+                clk->name);
+
+       v = omap2_clkdm_clktrctrl_read(clkdm);
+
+       if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+           (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+               _clkdm_add_autodeps(clkdm);
+       else
+               omap2_clkdm_wakeup(clkdm);
+
+       return 0;
+}
+
+/**
+ * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
+ * @clkdm: struct clockdomain *
+ * @clk: struct clk * of the disabled downstream clock
+ *
+ * Decrement the usecount of this clockdomain 'clkdm'. Intended to be
+ * called by clk_disable() code.  If the usecount goes to 0, put the
+ * clockdomain to sleep (software-supervised mode) or remove the
+ * clkdm-pwrdm autodependencies (hardware-supervised mode).  Returns
+ * -EINVAL if passed null pointers; -ERANGE if the clkdm usecount
+ * underflows and debugging is enabled; or returns 0 upon success or
+ * if the clockdomain is in hwsup idle mode.
+ */
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
+{
+       int v;
+
+       /*
+        * XXX Rewrite this code to maintain a list of enabled
+        * downstream clocks for debugging purposes?
+        */
+
+       if (!clkdm || !clk)
+               return -EINVAL;
+
+#ifdef DEBUG
+       if (atomic_read(&clkdm->usecount) == 0) {
+               WARN_ON(1); /* underflow */
+               return -ERANGE;
+       }
+#endif
+
+       if (atomic_dec_return(&clkdm->usecount) > 0)
+               return 0;
+
+       /* All downstream clocks of this clockdomain are now disabled */
+
+       pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
+                clk->name);
+
+       v = omap2_clkdm_clktrctrl_read(clkdm);
+
+       if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
+           (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+               _clkdm_del_autodeps(clkdm);
+       else
+               omap2_clkdm_sleep(clkdm);
+
+       return 0;
+}
+
diff --git a/arch/arm/mach-omap2/clockdomains.h b/arch/arm/mach-omap2/clockdomains.h
new file mode 100644 (file)
index 0000000..bafa650
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * OMAP2/3 clockdomains
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_H
+
+#include <mach/clockdomain.h>
+
+/*
+ * OMAP2/3-common clockdomains
+ *
+ * Even though the 2420 has a single PRCM module from the
+ * interconnect's perspective, internally it does appear to have
+ * separate PRM and CM clockdomains.  The usual test case is
+ * sys_clkout/sys_clkout2.
+ */
+
+static struct clockdomain prm_clkdm = {
+       .name           = "prm_clkdm",
+       .pwrdm          = { .name = "wkup_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain cm_clkdm = {
+       .name           = "cm_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+};
+
+/*
+ * virt_opp_clkdm is intended solely for use with virtual OPP clocks,
+ * e.g., virt_prcm_set, until OPP handling is rationalized.
+ */
+static struct clockdomain virt_opp_clkdm = {
+       .name           = "virt_opp_clkdm",
+       .pwrdm          = { .name = "wkup_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+/*
+ * 2420-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2420)
+
+static struct clockdomain mpu_2420_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm          = { .name = "mpu_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+static struct clockdomain iva1_2420_clkdm = {
+       .name           = "iva1_clkdm",
+       .pwrdm          = { .name = "dsp_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP2420_AUTOSTATE_IVA_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+#endif  /* CONFIG_ARCH_OMAP2420 */
+
+
+/*
+ * 2430-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP2430)
+
+static struct clockdomain mpu_2430_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm          = { .name = "mpu_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+static struct clockdomain mdm_clkdm = {
+       .name           = "mdm_clkdm",
+       .pwrdm          = { .name = "mdm_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP2430_AUTOSTATE_MDM_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+#endif    /* CONFIG_ARCH_OMAP2430 */
+
+
+/*
+ * 24XX-only clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP24XX)
+
+static struct clockdomain dsp_clkdm = {
+       .name           = "dsp_clkdm",
+       .pwrdm          = { .name = "dsp_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSP_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain gfx_24xx_clkdm = {
+       .name           = "gfx_clkdm",
+       .pwrdm          = { .name = "gfx_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_GFX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l3_24xx_clkdm = {
+       .name           = "core_l3_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_L3_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain core_l4_24xx_clkdm = {
+       .name           = "core_l4_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_L4_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+static struct clockdomain dss_24xx_clkdm = {
+       .name           = "dss_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP24XX_AUTOSTATE_DSS_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+};
+
+#endif   /* CONFIG_ARCH_OMAP24XX */
+
+
+/*
+ * 34xx clockdomains
+ */
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+
+static struct clockdomain mpu_34xx_clkdm = {
+       .name           = "mpu_clkdm",
+       .pwrdm          = { .name = "mpu_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP | CLKDM_CAN_FORCE_WAKEUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_MPU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain neon_clkdm = {
+       .name           = "neon_clkdm",
+       .pwrdm          = { .name = "neon_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_NEON_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain iva2_clkdm = {
+       .name           = "iva2_clkdm",
+       .pwrdm          = { .name = "iva2_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_IVA2_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain gfx_3430es1_clkdm = {
+       .name           = "gfx_clkdm",
+       .pwrdm          = { .name = "gfx_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_GFX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+};
+
+static struct clockdomain sgx_clkdm = {
+       .name           = "sgx_clkdm",
+       .pwrdm          = { .name = "sgx_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_SGX_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+/*
+ * The die-to-die clockdomain was documented in the 34xx ES1 TRM, but
+ * then that information was removed from the 34xx ES2+ TRM.  It is
+ * unclear whether the core is still there, but the clockdomain logic
+ * is there, and must be programmed to an appropriate state if the
+ * CORE clockdomain is to become inactive.
+ */
+static struct clockdomain d2d_clkdm = {
+       .name           = "d2d_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430ES1_CLKTRCTRL_D2D_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain core_l3_34xx_clkdm = {
+       .name           = "core_l3_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_L3_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain core_l4_34xx_clkdm = {
+       .name           = "core_l4_clkdm",
+       .pwrdm          = { .name = "core_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_L4_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dss_34xx_clkdm = {
+       .name           = "dss_clkdm",
+       .pwrdm          = { .name = "dss_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_DSS_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain cam_clkdm = {
+       .name           = "cam_clkdm",
+       .pwrdm          = { .name = "cam_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_CAM_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain usbhost_clkdm = {
+       .name           = "usbhost_clkdm",
+       .pwrdm          = { .name = "usbhost_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430ES2_CLKTRCTRL_USBHOST_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+static struct clockdomain per_clkdm = {
+       .name           = "per_clkdm",
+       .pwrdm          = { .name = "per_pwrdm" },
+       .flags          = CLKDM_CAN_HWSUP_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_PER_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain emu_clkdm = {
+       .name           = "emu_clkdm",
+       .pwrdm          = { .name = "emu_pwrdm" },
+       .flags          = CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_SWSUP,
+       .clktrctrl_mask = OMAP3430_CLKTRCTRL_EMU_MASK,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll1_clkdm = {
+       .name           = "dpll1_clkdm",
+       .pwrdm          = { .name = "dpll1_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll2_clkdm = {
+       .name           = "dpll2_clkdm",
+       .pwrdm          = { .name = "dpll2_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll3_clkdm = {
+       .name           = "dpll3_clkdm",
+       .pwrdm          = { .name = "dpll3_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll4_clkdm = {
+       .name           = "dpll4_clkdm",
+       .pwrdm          = { .name = "dpll4_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct clockdomain dpll5_clkdm = {
+       .name           = "dpll5_clkdm",
+       .pwrdm          = { .name = "dpll5_pwrdm" },
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+#endif   /* CONFIG_ARCH_OMAP34XX */
+
+/*
+ * Clockdomain-powerdomain hwsup dependencies (34XX only)
+ */
+
+static struct clkdm_pwrdm_autodep clkdm_pwrdm_autodeps[] = {
+       {
+               .pwrdm     = { .name = "mpu_pwrdm" },
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm     = { .name = "iva2_pwrdm" },
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm     = { .name = NULL },
+       }
+};
+
+/*
+ *
+ */
+
+static struct clockdomain *clockdomains_omap[] = {
+
+       &cm_clkdm,
+       &prm_clkdm,
+       &virt_opp_clkdm,
+
+#ifdef CONFIG_ARCH_OMAP2420
+       &mpu_2420_clkdm,
+       &iva1_2420_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+       &mpu_2430_clkdm,
+       &mdm_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+       &dsp_clkdm,
+       &gfx_24xx_clkdm,
+       &core_l3_24xx_clkdm,
+       &core_l4_24xx_clkdm,
+       &dss_24xx_clkdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+       &mpu_34xx_clkdm,
+       &neon_clkdm,
+       &iva2_clkdm,
+       &gfx_3430es1_clkdm,
+       &sgx_clkdm,
+       &d2d_clkdm,
+       &core_l3_34xx_clkdm,
+       &core_l4_34xx_clkdm,
+       &dss_34xx_clkdm,
+       &cam_clkdm,
+       &usbhost_clkdm,
+       &per_clkdm,
+       &emu_clkdm,
+       &dpll1_clkdm,
+       &dpll2_clkdm,
+       &dpll3_clkdm,
+       &dpll4_clkdm,
+       &dpll5_clkdm,
+#endif
+
+       NULL,
+};
+
+#endif
index 20ac38100678a1eb2c82d5b7e76aaddd7bb9be2b..a9a0df522ca3882f940a729653dadbdfcc50b6e2 100644 (file)
@@ -63,7 +63,8 @@
 #define OMAP24XX_CLKSEL_MPU_MASK                       (0x1f << 0)
 
 /* CM_CLKSTCTRL_MPU */
-#define OMAP24XX_AUTOSTATE_MPU                         (1 << 0)
+#define OMAP24XX_AUTOSTATE_MPU_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_MPU_MASK                    (1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits*/
 #define OMAP24XX_EN_TV_SHIFT                           2
 #define OMAP24XX_EN_DES                                        (1 << 0)
 
 /* CM_IDLEST1_CORE specific bits */
-#define OMAP24XX_ST_MAILBOXES                          (1 << 30)
-#define OMAP24XX_ST_WDT4                               (1 << 29)
-#define OMAP2420_ST_WDT3                               (1 << 28)
-#define OMAP24XX_ST_MSPRO                              (1 << 27)
-#define OMAP24XX_ST_FAC                                        (1 << 25)
-#define OMAP2420_ST_EAC                                        (1 << 24)
-#define OMAP24XX_ST_HDQ                                        (1 << 23)
-#define OMAP24XX_ST_I2C2                               (1 << 20)
-#define OMAP24XX_ST_I2C1                               (1 << 19)
-#define OMAP24XX_ST_MCBSP2                             (1 << 16)
-#define OMAP24XX_ST_MCBSP1                             (1 << 15)
-#define OMAP24XX_ST_DSS                                        (1 << 0)
+#define OMAP24XX_ST_MAILBOXES_SHIFT                    30
+#define OMAP24XX_ST_MAILBOXES_MASK                     (1 << 30)
+#define OMAP24XX_ST_WDT4_SHIFT                         29
+#define OMAP24XX_ST_WDT4_MASK                          (1 << 29)
+#define OMAP2420_ST_WDT3_SHIFT                         28
+#define OMAP2420_ST_WDT3_MASK                          (1 << 28)
+#define OMAP24XX_ST_MSPRO_SHIFT                                27
+#define OMAP24XX_ST_MSPRO_MASK                         (1 << 27)
+#define OMAP24XX_ST_FAC_SHIFT                          25
+#define OMAP24XX_ST_FAC_MASK                           (1 << 25)
+#define OMAP2420_ST_EAC_SHIFT                          24
+#define OMAP2420_ST_EAC_MASK                           (1 << 24)
+#define OMAP24XX_ST_HDQ_SHIFT                          23
+#define OMAP24XX_ST_HDQ_MASK                           (1 << 23)
+#define OMAP2420_ST_I2C2_SHIFT                         20
+#define OMAP2420_ST_I2C2_MASK                          (1 << 20)
+#define OMAP2420_ST_I2C1_SHIFT                         19
+#define OMAP2420_ST_I2C1_MASK                          (1 << 19)
+#define OMAP24XX_ST_MCBSP2_SHIFT                       16
+#define OMAP24XX_ST_MCBSP2_MASK                                (1 << 16)
+#define OMAP24XX_ST_MCBSP1_SHIFT                       15
+#define OMAP24XX_ST_MCBSP1_MASK                                (1 << 15)
+#define OMAP24XX_ST_DSS_SHIFT                          0
+#define OMAP24XX_ST_DSS_MASK                           (1 << 0)
 
 /* CM_IDLEST2_CORE */
-#define OMAP2430_ST_MCBSP5                             (1 << 5)
-#define OMAP2430_ST_MCBSP4                             (1 << 4)
-#define OMAP2430_ST_MCBSP3                             (1 << 3)
-#define OMAP24XX_ST_SSI                                        (1 << 1)
+#define OMAP2430_ST_MCBSP5_SHIFT                       5
+#define OMAP2430_ST_MCBSP5_MASK                                (1 << 5)
+#define OMAP2430_ST_MCBSP4_SHIFT                               4
+#define OMAP2430_ST_MCBSP4_MASK                                (1 << 4)
+#define OMAP2430_ST_MCBSP3_SHIFT                               3
+#define OMAP2430_ST_MCBSP3_MASK                                (1 << 3)
+#define OMAP24XX_ST_SSI_SHIFT                          1
+#define OMAP24XX_ST_SSI_MASK                           (1 << 1)
 
 /* CM_IDLEST3_CORE */
 /* 2430 only */
-#define OMAP2430_ST_SDRC                               (1 << 2)
+#define OMAP2430_ST_SDRC_SHIFT                         2
+#define OMAP2430_ST_SDRC_MASK                          (1 << 2)
 
 /* CM_IDLEST4_CORE */
-#define OMAP24XX_ST_PKA                                        (1 << 4)
-#define OMAP24XX_ST_AES                                        (1 << 3)
-#define OMAP24XX_ST_RNG                                        (1 << 2)
-#define OMAP24XX_ST_SHA                                        (1 << 1)
-#define OMAP24XX_ST_DES                                        (1 << 0)
+#define OMAP24XX_ST_PKA_SHIFT                          4
+#define OMAP24XX_ST_PKA_MASK                           (1 << 4)
+#define OMAP24XX_ST_AES_SHIFT                          3
+#define OMAP24XX_ST_AES_MASK                           (1 << 3)
+#define OMAP24XX_ST_RNG_SHIFT                          2
+#define OMAP24XX_ST_RNG_MASK                           (1 << 2)
+#define OMAP24XX_ST_SHA_SHIFT                          1
+#define OMAP24XX_ST_SHA_MASK                           (1 << 1)
+#define OMAP24XX_ST_DES_SHIFT                          0
+#define OMAP24XX_ST_DES_MASK                           (1 << 0)
 
 /* CM_AUTOIDLE1_CORE */
 #define OMAP24XX_AUTO_CAM                              (1 << 31)
 #define OMAP24XX_CLKSEL_GPT2_MASK                      (0x3 << 2)
 
 /* CM_CLKSTCTRL_CORE */
-#define OMAP24XX_AUTOSTATE_DSS                         (1 << 2)
-#define OMAP24XX_AUTOSTATE_L4                          (1 << 1)
-#define OMAP24XX_AUTOSTATE_L3                          (1 << 0)
+#define OMAP24XX_AUTOSTATE_DSS_SHIFT                   2
+#define OMAP24XX_AUTOSTATE_DSS_MASK                    (1 << 2)
+#define OMAP24XX_AUTOSTATE_L4_SHIFT                    1
+#define OMAP24XX_AUTOSTATE_L4_MASK                     (1 << 1)
+#define OMAP24XX_AUTOSTATE_L3_SHIFT                    0
+#define OMAP24XX_AUTOSTATE_L3_MASK                     (1 << 0)
 
 /* CM_FCLKEN_GFX */
 #define OMAP24XX_EN_3D_SHIFT                           2
 /* CM_CLKSEL_GFX specific bits */
 
 /* CM_CLKSTCTRL_GFX */
-#define OMAP24XX_AUTOSTATE_GFX                         (1 << 0)
+#define OMAP24XX_AUTOSTATE_GFX_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_GFX_MASK                    (1 << 0)
 
 /* CM_FCLKEN_WKUP specific bits */
 
 #define OMAP24XX_EN_32KSYNC                            (1 << 1)
 
 /* CM_IDLEST_WKUP specific bits */
-#define OMAP2430_ST_ICR                                        (1 << 6)
-#define OMAP24XX_ST_OMAPCTRL                           (1 << 5)
-#define OMAP24XX_ST_WDT1                               (1 << 4)
-#define OMAP24XX_ST_MPU_WDT                            (1 << 3)
-#define OMAP24XX_ST_32KSYNC                            (1 << 1)
+#define OMAP2430_ST_ICR_SHIFT                          6
+#define OMAP2430_ST_ICR_MASK                           (1 << 6)
+#define OMAP24XX_ST_OMAPCTRL_SHIFT                     5
+#define OMAP24XX_ST_OMAPCTRL_MASK                      (1 << 5)
+#define OMAP24XX_ST_WDT1_SHIFT                         4
+#define OMAP24XX_ST_WDT1_MASK                          (1 << 4)
+#define OMAP24XX_ST_MPU_WDT_SHIFT                      3
+#define OMAP24XX_ST_MPU_WDT_MASK                       (1 << 3)
+#define OMAP24XX_ST_32KSYNC_SHIFT                      1
+#define OMAP24XX_ST_32KSYNC_MASK                       (1 << 1)
 
 /* CM_AUTOIDLE_WKUP */
 #define OMAP24XX_AUTO_OMAPCTRL                         (1 << 5)
 #define OMAP24XX_CLKSEL_DSP_MASK                       (0x1f << 0)
 
 /* CM_CLKSTCTRL_DSP */
-#define OMAP2420_AUTOSTATE_IVA                         (1 << 8)
-#define OMAP24XX_AUTOSTATE_DSP                         (1 << 0)
+#define OMAP2420_AUTOSTATE_IVA_SHIFT                   8
+#define OMAP2420_AUTOSTATE_IVA_MASK                    (1 << 8)
+#define OMAP24XX_AUTOSTATE_DSP_SHIFT                   0
+#define OMAP24XX_AUTOSTATE_DSP_MASK                    (1 << 0)
 
 /* CM_FCLKEN_MDM */
 /* 2430 only */
 
 /* CM_CLKSTCTRL_MDM */
 /* 2430 only */
-#define OMAP2430_AUTOSTATE_MDM                         (1 << 0)
+#define OMAP2430_AUTOSTATE_MDM_SHIFT                   0
+#define OMAP2430_AUTOSTATE_MDM_MASK                    (1 << 0)
 
 #endif
index ee4c0ca1a7087af06ad8bb45498accbeb67f2cea..6f3f5a36aae664960e037d59200dba8fe025feab 100644 (file)
@@ -96,7 +96,8 @@
 #define OMAP3430_CLKTRCTRL_IVA2_MASK                   (0x3 << 0)
 
 /* CM_CLKSTST_IVA2 */
-#define OMAP3430_CLKACTIVITY_IVA2                      (1 << 0)
+#define OMAP3430_CLKACTIVITY_IVA2_SHIFT                        0
+#define OMAP3430_CLKACTIVITY_IVA2_MASK                 (1 << 0)
 
 /* CM_REVISION specific bits */
 
 #define OMAP3430_CLKTRCTRL_MPU_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_MPU */
-#define OMAP3430_CLKACTIVITY_MPU                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_MPU_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_MPU_MASK                  (1 << 0)
 
 /* CM_FCLKEN1_CORE specific bits */
 
 #define OMAP3430ES2_EN_CPEFUSE_MASK                    (1 << 0)
 
 /* CM_IDLEST1_CORE specific bits */
-#define OMAP3430_ST_ICR                                        (1 << 29)
-#define OMAP3430_ST_AES2                               (1 << 28)
-#define OMAP3430_ST_SHA12                              (1 << 27)
-#define OMAP3430_ST_DES2                               (1 << 26)
-#define OMAP3430_ST_MSPRO                              (1 << 23)
-#define OMAP3430_ST_HDQ                                        (1 << 22)
-#define OMAP3430ES1_ST_FAC                             (1 << 8)
-#define OMAP3430ES1_ST_MAILBOXES                       (1 << 7)
-#define OMAP3430_ST_OMAPCTRL                           (1 << 6)
-#define OMAP3430_ST_SDMA                               (1 << 2)
-#define OMAP3430_ST_SDRC                               (1 << 1)
-#define OMAP3430_ST_SSI                                        (1 << 0)
+#define OMAP3430ES2_ST_MMC3_SHIFT                      30
+#define OMAP3430ES2_ST_MMC3_MASK                       (1 << 30)
+#define OMAP3430_ST_ICR_SHIFT                          29
+#define OMAP3430_ST_ICR_MASK                           (1 << 29)
+#define OMAP3430_ST_AES2_SHIFT                         28
+#define OMAP3430_ST_AES2_MASK                          (1 << 28)
+#define OMAP3430_ST_SHA12_SHIFT                                27
+#define OMAP3430_ST_SHA12_MASK                         (1 << 27)
+#define OMAP3430_ST_DES2_SHIFT                         26
+#define OMAP3430_ST_DES2_MASK                          (1 << 26)
+#define OMAP3430_ST_MSPRO_SHIFT                                23
+#define OMAP3430_ST_MSPRO_MASK                         (1 << 23)
+#define OMAP3430_ST_HDQ_SHIFT                          22
+#define OMAP3430_ST_HDQ_MASK                           (1 << 22)
+#define OMAP3430ES1_ST_FAC_SHIFT                       8
+#define OMAP3430ES1_ST_FAC_MASK                                (1 << 8)
+#define OMAP3430ES2_ST_SSI_IDLE_SHIFT                  8
+#define OMAP3430ES2_ST_SSI_IDLE_MASK                   (1 << 8)
+#define OMAP3430_ST_MAILBOXES_SHIFT                    7
+#define OMAP3430_ST_MAILBOXES_MASK                     (1 << 7)
+#define OMAP3430_ST_OMAPCTRL_SHIFT                     6
+#define OMAP3430_ST_OMAPCTRL_MASK                      (1 << 6)
+#define OMAP3430_ST_SDMA_SHIFT                         2
+#define OMAP3430_ST_SDMA_MASK                          (1 << 2)
+#define OMAP3430_ST_SDRC_SHIFT                         1
+#define OMAP3430_ST_SDRC_MASK                          (1 << 1)
+#define OMAP3430_ST_SSI_STDBY_SHIFT                    0
+#define OMAP3430_ST_SSI_STDBY_MASK                     (1 << 0)
 
 /* CM_IDLEST2_CORE */
-#define OMAP3430_ST_PKA                                        (1 << 4)
-#define OMAP3430_ST_AES1                               (1 << 3)
-#define OMAP3430_ST_RNG                                        (1 << 2)
-#define OMAP3430_ST_SHA11                              (1 << 1)
-#define OMAP3430_ST_DES1                               (1 << 0)
+#define OMAP3430_ST_PKA_SHIFT                          4
+#define OMAP3430_ST_PKA_MASK                           (1 << 4)
+#define OMAP3430_ST_AES1_SHIFT                         3
+#define OMAP3430_ST_AES1_MASK                          (1 << 3)
+#define OMAP3430_ST_RNG_SHIFT                          2
+#define OMAP3430_ST_RNG_MASK                           (1 << 2)
+#define OMAP3430_ST_SHA11_SHIFT                                1
+#define OMAP3430_ST_SHA11_MASK                         (1 << 1)
+#define OMAP3430_ST_DES1_SHIFT                         0
+#define OMAP3430_ST_DES1_MASK                          (1 << 0)
 
 /* CM_IDLEST3_CORE */
 #define OMAP3430ES2_ST_USBTLL_SHIFT                    2
 #define OMAP3430ES2_ST_USBTLL_MASK                     (1 << 2)
+#define OMAP3430ES2_ST_CPEFUSE_SHIFT                   0
+#define OMAP3430ES2_ST_CPEFUSE_MASK                    (1 << 0)
 
 /* CM_AUTOIDLE1_CORE */
+#define OMAP3430ES2_AUTO_MMC3                          (1 << 30)
+#define OMAP3430ES2_AUTO_MMC3_SHIFT                    30
+#define OMAP3430ES2_AUTO_ICR                           (1 << 29)
+#define OMAP3430ES2_AUTO_ICR_SHIFT                     29
 #define OMAP3430_AUTO_AES2                             (1 << 28)
 #define OMAP3430_AUTO_AES2_SHIFT                       28
 #define OMAP3430_AUTO_SHA12                            (1 << 27)
 #define OMAP3430_AUTO_DES1_SHIFT                       0
 
 /* CM_AUTOIDLE3_CORE */
+#define        OMAP3430ES2_AUTO_USBHOST                        (1 << 0)
+#define        OMAP3430ES2_AUTO_USBHOST_SHIFT                  0
+#define        OMAP3430ES2_AUTO_USBTLL                         (1 << 2)
 #define OMAP3430ES2_AUTO_USBTLL_SHIFT                  2
 #define OMAP3430ES2_AUTO_USBTLL_MASK                   (1 << 2)
 
 #define OMAP3430_CLKTRCTRL_L3_MASK                     (0x3 << 0)
 
 /* CM_CLKSTST_CORE */
-#define OMAP3430ES1_CLKACTIVITY_D2D                    (1 << 2)
-#define OMAP3430_CLKACTIVITY_L4                                (1 << 1)
-#define OMAP3430_CLKACTIVITY_L3                                (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_D2D_SHIFT              2
+#define OMAP3430ES1_CLKACTIVITY_D2D_MASK               (1 << 2)
+#define OMAP3430_CLKACTIVITY_L4_SHIFT                  1
+#define OMAP3430_CLKACTIVITY_L4_MASK                   (1 << 1)
+#define OMAP3430_CLKACTIVITY_L3_SHIFT                  0
+#define OMAP3430_CLKACTIVITY_L3_MASK                   (1 << 0)
 
 /* CM_FCLKEN_GFX */
 #define OMAP3430ES1_EN_3D                              (1 << 2)
 #define OMAP3430ES1_CLKTRCTRL_GFX_MASK                 (0x3 << 0)
 
 /* CM_CLKSTST_GFX */
-#define OMAP3430ES1_CLKACTIVITY_GFX                    (1 << 0)
+#define OMAP3430ES1_CLKACTIVITY_GFX_SHIFT              0
+#define OMAP3430ES1_CLKACTIVITY_GFX_MASK               (1 << 0)
 
 /* CM_FCLKEN_SGX */
-#define OMAP3430ES2_EN_SGX_SHIFT                       1
-#define OMAP3430ES2_EN_SGX_MASK                                (1 << 1)
+#define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_SHIFT         1
+#define OMAP3430ES2_CM_FCLKEN_SGX_EN_SGX_MASK          (1 << 1)
+
+/* CM_ICLKEN_SGX */
+#define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_SHIFT         0
+#define OMAP3430ES2_CM_ICLKEN_SGX_EN_SGX_MASK          (1 << 0)
 
 /* CM_CLKSEL_SGX */
 #define OMAP3430ES2_CLKSEL_SGX_SHIFT                   0
 #define OMAP3430ES2_CLKSEL_SGX_MASK                    (0x7 << 0)
 
+/* CM_CLKSTCTRL_SGX */
+#define OMAP3430ES2_CLKTRCTRL_SGX_SHIFT                        0
+#define OMAP3430ES2_CLKTRCTRL_SGX_MASK                 (0x3 << 0)
+
+/* CM_CLKSTST_SGX */
+#define OMAP3430ES2_CLKACTIVITY_SGX_SHIFT              0
+#define OMAP3430ES2_CLKACTIVITY_SGX_MASK               (1 << 0)
+
 /* CM_FCLKEN_WKUP specific bits */
 #define OMAP3430ES2_EN_USIMOCP_SHIFT                   9
+#define OMAP3430ES2_EN_USIMOCP_MASK                    (1 << 9)
 
 /* CM_ICLKEN_WKUP specific bits */
 #define OMAP3430_EN_WDT1                               (1 << 4)
 #define OMAP3430_EN_32KSYNC_SHIFT                      2
 
 /* CM_IDLEST_WKUP specific bits */
-#define OMAP3430_ST_WDT2                               (1 << 5)
-#define OMAP3430_ST_WDT1                               (1 << 4)
-#define OMAP3430_ST_32KSYNC                            (1 << 2)
+#define OMAP3430ES2_ST_USIMOCP_SHIFT                   9
+#define OMAP3430ES2_ST_USIMOCP_MASK                    (1 << 9)
+#define OMAP3430_ST_WDT2_SHIFT                         5
+#define OMAP3430_ST_WDT2_MASK                          (1 << 5)
+#define OMAP3430_ST_WDT1_SHIFT                         4
+#define OMAP3430_ST_WDT1_MASK                          (1 << 4)
+#define OMAP3430_ST_32KSYNC_SHIFT                      2
+#define OMAP3430_ST_32KSYNC_MASK                       (1 << 2)
 
 /* CM_AUTOIDLE_WKUP */
+#define OMAP3430ES2_AUTO_USIMOCP                               (1 << 9)
+#define OMAP3430ES2_AUTO_USIMOCP_SHIFT                 9
 #define OMAP3430_AUTO_WDT2                             (1 << 5)
 #define OMAP3430_AUTO_WDT2_SHIFT                       5
 #define OMAP3430_AUTO_WDT1                             (1 << 4)
 #define OMAP3430_ST_CORE_CLK_MASK                      (1 << 0)
 
 /* CM_IDLEST2_CKGEN */
+#define OMAP3430ES2_ST_USIM_CLK_SHIFT                  2
+#define OMAP3430ES2_ST_USIM_CLK_MASK                   (1 << 2)
 #define OMAP3430ES2_ST_120M_CLK_SHIFT                  1
 #define OMAP3430ES2_ST_120M_CLK_MASK                   (1 << 1)
 #define OMAP3430ES2_ST_PERIPH2_CLK_SHIFT               0
 #define OMAP3430_CORE_DPLL_MULT_MASK                   (0x7ff << 16)
 #define OMAP3430_CORE_DPLL_DIV_SHIFT                   8
 #define OMAP3430_CORE_DPLL_DIV_MASK                    (0x7f << 8)
-#define OMAP3430_SOURCE_54M                            (1 << 5)
-#define OMAP3430_SOURCE_48M                            (1 << 3)
+#define OMAP3430_SOURCE_96M_SHIFT                      6
+#define OMAP3430_SOURCE_96M_MASK                       (1 << 6)
+#define OMAP3430_SOURCE_54M_SHIFT                      5
+#define OMAP3430_SOURCE_54M_MASK                       (1 << 5)
+#define OMAP3430_SOURCE_48M_SHIFT                      3
+#define OMAP3430_SOURCE_48M_MASK                       (1 << 3)
 
 /* CM_CLKSEL2_PLL */
 #define OMAP3430_PERIPH_DPLL_MULT_SHIFT                        8
 #define OMAP3430_CM_ICLKEN_DSS_EN_DSS_SHIFT            0
 
 /* CM_IDLEST_DSS */
-#define OMAP3430_ST_DSS                                        (1 << 0)
+#define OMAP3430ES2_ST_DSS_IDLE_SHIFT                  1
+#define OMAP3430ES2_ST_DSS_IDLE_MASK                   (1 << 1)
+#define OMAP3430ES2_ST_DSS_STDBY_SHIFT                 0
+#define OMAP3430ES2_ST_DSS_STDBY_MASK                  (1 << 0)
+#define OMAP3430ES1_ST_DSS_SHIFT                       0
+#define OMAP3430ES1_ST_DSS_MASK                                (1 << 0)
 
 /* CM_AUTOIDLE_DSS */
 #define OMAP3430_AUTO_DSS                              (1 << 0)
 #define OMAP3430_CLKTRCTRL_DSS_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_DSS */
-#define OMAP3430_CLKACTIVITY_DSS                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_DSS_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_DSS_MASK                  (1 << 0)
 
 /* CM_FCLKEN_CAM specific bits */
+#define OMAP3430_EN_CSI2                               (1 << 1)
+#define OMAP3430_EN_CSI2_SHIFT                         1
 
 /* CM_ICLKEN_CAM specific bits */
 
 #define OMAP3430_CLKTRCTRL_CAM_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_CAM */
-#define OMAP3430_CLKACTIVITY_CAM                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_CAM_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_CAM_MASK                  (1 << 0)
 
 /* CM_FCLKEN_PER specific bits */
 
 /* CM_ICLKEN_PER specific bits */
 
 /* CM_IDLEST_PER */
-#define OMAP3430_ST_WDT3                               (1 << 12)
-#define OMAP3430_ST_MCBSP4                             (1 << 2)
-#define OMAP3430_ST_MCBSP3                             (1 << 1)
-#define OMAP3430_ST_MCBSP2                             (1 << 0)
+#define OMAP3430_ST_WDT3_SHIFT                         12
+#define OMAP3430_ST_WDT3_MASK                          (1 << 12)
+#define OMAP3430_ST_MCBSP4_SHIFT                       2
+#define OMAP3430_ST_MCBSP4_MASK                                (1 << 2)
+#define OMAP3430_ST_MCBSP3_SHIFT                       1
+#define OMAP3430_ST_MCBSP3_MASK                                (1 << 1)
+#define OMAP3430_ST_MCBSP2_SHIFT                       0
+#define OMAP3430_ST_MCBSP2_MASK                                (1 << 0)
 
 /* CM_AUTOIDLE_PER */
 #define OMAP3430_AUTO_GPIO6                            (1 << 17)
 #define OMAP3430_CLKTRCTRL_PER_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_PER */
-#define OMAP3430_CLKACTIVITY_PER                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_PER_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_PER_MASK                  (1 << 0)
 
 /* CM_CLKSEL1_EMU */
 #define OMAP3430_DIV_DPLL4_SHIFT                       24
 #define OMAP3430_CLKTRCTRL_EMU_MASK                    (0x3 << 0)
 
 /* CM_CLKSTST_EMU */
-#define OMAP3430_CLKACTIVITY_EMU                       (1 << 0)
+#define OMAP3430_CLKACTIVITY_EMU_SHIFT                 0
+#define OMAP3430_CLKACTIVITY_EMU_MASK                  (1 << 0)
 
 /* CM_CLKSEL2_EMU specific bits */
 #define OMAP3430_CORE_DPLL_EMU_MULT_SHIFT              8
 #define OMAP3430ES2_EN_USBHOST_MASK                    (1 << 0)
 
 /* CM_IDLEST_USBHOST */
+#define OMAP3430ES2_ST_USBHOST_IDLE_SHIFT              1
+#define OMAP3430ES2_ST_USBHOST_IDLE_MASK               (1 << 1)
+#define OMAP3430ES2_ST_USBHOST_STDBY_SHIFT             0
+#define OMAP3430ES2_ST_USBHOST_STDBY_MASK              (1 << 0)
 
 /* CM_AUTOIDLE_USBHOST */
 #define OMAP3430ES2_AUTO_USBHOST_SHIFT                 0
 #define OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT            0
 #define OMAP3430ES2_CLKTRCTRL_USBHOST_MASK             (3 << 0)
 
-
+/* CM_CLKSTST_USBHOST */
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_SHIFT          0
+#define OMAP3430ES2_CLKACTIVITY_USBHOST_MASK           (1 << 0)
 
 #endif
index 87a44c715aa4dd1b0604f4f81874c15df9de5d7b..7750becd5d37c692295c29feb2037726460e003f 100644 (file)
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_CM_REGADDR(module, reg)                                   \
-       (void __iomem *)IO_ADDRESS(OMAP2_CM_BASE + (module) + (reg))
-#else
 #define OMAP2420_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP2420_CM_BASE + (module) + (reg))
 #define OMAP2430_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP2430_CM_BASE + (module) + (reg))
 #define OMAP34XX_CM_REGADDR(module, reg)                               \
                        IO_ADDRESS(OMAP3430_CM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global CM registers
- * Use cm_{read,write}_reg() with these registers.
+ * Use __raw_{read,write}l() with these registers.
  * These registers appear once per CM module.
  */
 
-#define OMAP3430_CM_REVISION           OMAP_CM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP3430_CM_SYSCONFIG          OMAP_CM_REGADDR(OCP_MOD, 0x0010)
-#define OMAP3430_CM_POLCTRL            OMAP_CM_REGADDR(OCP_MOD, 0x009c)
+#define OMAP3430_CM_REVISION           OMAP34XX_CM_REGADDR(OCP_MOD, 0x0000)
+#define OMAP3430_CM_SYSCONFIG          OMAP34XX_CM_REGADDR(OCP_MOD, 0x0010)
+#define OMAP3430_CM_POLCTRL            OMAP34XX_CM_REGADDR(OCP_MOD, 0x009c)
 
-#define OMAP3430_CM_CLKOUT_CTRL                OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP3430_CM_CLKOUT_CTRL_OFFSET                 0x0070
 
 /*
  * Module specific CM registers from CM_BASE + domain offset
@@ -67,7 +62,6 @@
 #define CM_CLKSEL2                                     0x0044
 #define CM_CLKSTCTRL                                   0x0048
 
-
 /* Architecture-specific registers */
 
 #define OMAP24XX_CM_FCLKEN2                            0x0004
index 7a7f02559075fc9ce8538c5f64d26c538ef03bc3..32550a55fa4db8cf7ae7a9b657c62f275f00cae0 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
+#include <mach/control.h>
 #include <mach/tc.h>
 #include <mach/board.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
+#include <mach/eac.h>
+#include <mach/mmc.h>
 
-#if    defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
 
-#define OMAP2_I2C_BASE2                0x48072000
-#define OMAP2_I2C_INT2         57
-
-static struct resource i2c_resources2[] = {
+static struct resource cam_resources[] = {
        {
-               .start          = OMAP2_I2C_BASE2,
-               .end            = OMAP2_I2C_BASE2 + 0x3f,
+               .start          = OMAP24XX_CAMERA_BASE,
+               .end            = OMAP24XX_CAMERA_BASE + 0xfff,
                .flags          = IORESOURCE_MEM,
        },
        {
-               .start          = OMAP2_I2C_INT2,
+               .start          = INT_24XX_CAM_IRQ,
                .flags          = IORESOURCE_IRQ,
-       },
+       }
 };
 
-static struct platform_device omap_i2c_device2 = {
-       .name           = "i2c_omap",
-       .id             = 2,
-       .num_resources  = ARRAY_SIZE(i2c_resources2),
-       .resource       = i2c_resources2,
+static struct platform_device omap_cam_device = {
+       .name           = "omap24xxcam",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(cam_resources),
+       .resource       = cam_resources,
 };
 
-/* See also arch/arm/plat-omap/devices.c for first I2C on 24xx */
-static void omap_init_i2c(void)
+static inline void omap_init_camera(void)
 {
-       /* REVISIT: Second I2C not in use on H4? */
-       if (machine_is_omap_h4())
-               return;
-
-       if (!cpu_is_omap2430()) {
-               omap_cfg_reg(J15_24XX_I2C2_SCL);
-               omap_cfg_reg(H19_24XX_I2C2_SDA);
-       }
-       (void) platform_device_register(&omap_i2c_device2);
+       platform_device_register(&omap_cam_device);
 }
 
-#else
+#elif defined(CONFIG_VIDEO_OMAP3) || defined(CONFIG_VIDEO_OMAP3_MODULE)
 
-static void omap_init_i2c(void) {}
+static struct resource cam_resources[] = {
+       {
+               .start          = OMAP34XX_CAMERA_BASE,
+               .end            = OMAP34XX_CAMERA_BASE + 0x1B70,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_34XX_CAM_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       }
+};
 
+static struct platform_device omap_cam_device = {
+       .name           = "omap34xxcam",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(cam_resources),
+       .resource       = cam_resources,
+};
+
+static inline void omap_init_camera(void)
+{
+       platform_device_register(&omap_cam_device);
+}
+#else
+static inline void omap_init_camera(void)
+{
+}
 #endif
 
 #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
@@ -104,7 +120,9 @@ static inline void omap_init_mbox(void) { }
 
 #if defined(CONFIG_OMAP_STI)
 
-#define OMAP2_STI_BASE         IO_ADDRESS(0x48068000)
+#if defined(CONFIG_ARCH_OMAP2)
+
+#define OMAP2_STI_BASE         0x48068000
 #define OMAP2_STI_CHANNEL_BASE 0x54000000
 #define OMAP2_STI_IRQ          4
 
@@ -124,6 +142,25 @@ static struct resource sti_resources[] = {
                .flags          = IORESOURCE_IRQ,
        }
 };
+#elif defined(CONFIG_ARCH_OMAP3)
+
+#define OMAP3_SDTI_BASE                0x54500000
+#define OMAP3_SDTI_CHANNEL_BASE        0x54600000
+
+static struct resource sti_resources[] = {
+       {
+               .start          = OMAP3_SDTI_BASE,
+               .end            = OMAP3_SDTI_BASE + 0xFFF,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = OMAP3_SDTI_CHANNEL_BASE,
+               .end            = OMAP3_SDTI_CHANNEL_BASE + SZ_1M - 1,
+               .flags          = IORESOURCE_MEM,
+       }
+};
+
+#endif
 
 static struct platform_device sti_device = {
        .name           = "sti",
@@ -140,12 +177,14 @@ static inline void omap_init_sti(void)
 static inline void omap_init_sti(void) {}
 #endif
 
-#if defined(CONFIG_SPI_OMAP24XX)
+#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
 
 #include <mach/mcspi.h>
 
 #define OMAP2_MCSPI1_BASE              0x48098000
 #define OMAP2_MCSPI2_BASE              0x4809a000
+#define OMAP2_MCSPI3_BASE              0x480b8000
+#define OMAP2_MCSPI4_BASE              0x480ba000
 
 static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
        .num_cs         = 4,
@@ -159,7 +198,7 @@ static struct resource omap2_mcspi1_resources[] = {
        },
 };
 
-struct platform_device omap2_mcspi1 = {
+static struct platform_device omap2_mcspi1 = {
        .name           = "omap2_mcspi",
        .id             = 1,
        .num_resources  = ARRAY_SIZE(omap2_mcspi1_resources),
@@ -181,7 +220,7 @@ static struct resource omap2_mcspi2_resources[] = {
        },
 };
 
-struct platform_device omap2_mcspi2 = {
+static struct platform_device omap2_mcspi2 = {
        .name           = "omap2_mcspi",
        .id             = 2,
        .num_resources  = ARRAY_SIZE(omap2_mcspi2_resources),
@@ -191,16 +230,246 @@ struct platform_device omap2_mcspi2 = {
        },
 };
 
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+static struct omap2_mcspi_platform_config omap2_mcspi3_config = {
+       .num_cs         = 2,
+};
+
+static struct resource omap2_mcspi3_resources[] = {
+       {
+       .start          = OMAP2_MCSPI3_BASE,
+       .end            = OMAP2_MCSPI3_BASE + 0xff,
+       .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_mcspi3 = {
+       .name           = "omap2_mcspi",
+       .id             = 3,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi3_resources),
+       .resource       = omap2_mcspi3_resources,
+       .dev            = {
+               .platform_data = &omap2_mcspi3_config,
+       },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static struct omap2_mcspi_platform_config omap2_mcspi4_config = {
+       .num_cs         = 1,
+};
+
+static struct resource omap2_mcspi4_resources[] = {
+       {
+               .start          = OMAP2_MCSPI4_BASE,
+               .end            = OMAP2_MCSPI4_BASE + 0xff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_mcspi4 = {
+       .name           = "omap2_mcspi",
+       .id             = 4,
+       .num_resources  = ARRAY_SIZE(omap2_mcspi4_resources),
+       .resource       = omap2_mcspi4_resources,
+       .dev            = {
+               .platform_data = &omap2_mcspi4_config,
+       },
+};
+#endif
+
 static void omap_init_mcspi(void)
 {
        platform_device_register(&omap2_mcspi1);
        platform_device_register(&omap2_mcspi2);
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3)
+       if (cpu_is_omap2430() || cpu_is_omap343x())
+               platform_device_register(&omap2_mcspi3);
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       if (cpu_is_omap343x())
+               platform_device_register(&omap2_mcspi4);
+#endif
 }
 
 #else
 static inline void omap_init_mcspi(void) {}
 #endif
 
+#ifdef CONFIG_SND_OMAP24XX_EAC
+
+#define OMAP2_EAC_BASE                 (L4_24XX_BASE + 0x90000)
+
+static struct resource omap2_eac_resources[] = {
+       {
+               .start          = OMAP2_EAC_BASE,
+               .end            = OMAP2_EAC_BASE + 0xfff,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device omap2_eac_device = {
+       .name           = "omap24xx-eac",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(omap2_eac_resources),
+       .resource       = omap2_eac_resources,
+       .dev = {
+               .platform_data = NULL,
+       },
+};
+
+void omap_init_eac(struct eac_platform_data *pdata)
+{
+       omap2_eac_device.dev.platform_data = pdata;
+       platform_device_register(&omap2_eac_device);
+}
+
+#else
+void omap_init_eac(struct eac_platform_data *pdata) {}
+#endif
+
+#ifdef CONFIG_OMAP_SHA1_MD5
+static struct resource sha1_md5_resources[] = {
+       {
+               .start  = OMAP24XX_SEC_SHA1MD5_BASE,
+               .end    = OMAP24XX_SEC_SHA1MD5_BASE + 0x64,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = INT_24XX_SHA1MD5,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device sha1_md5_device = {
+       .name           = "OMAP SHA1/MD5",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(sha1_md5_resources),
+       .resource       = sha1_md5_resources,
+};
+
+static void omap_init_sha1_md5(void)
+{
+       platform_device_register(&sha1_md5_device);
+}
+#else
+static inline void omap_init_sha1_md5(void) { }
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if    defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
+       defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+
+static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
+                       int controller_nr)
+{
+       if (cpu_is_omap2420() && controller_nr == 0) {
+               omap_cfg_reg(H18_24XX_MMC_CMD);
+               omap_cfg_reg(H15_24XX_MMC_CLKI);
+               omap_cfg_reg(G19_24XX_MMC_CLKO);
+               omap_cfg_reg(F20_24XX_MMC_DAT0);
+               omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
+               omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
+               if (mmc_controller->slots[0].wire4) {
+                       omap_cfg_reg(H14_24XX_MMC_DAT1);
+                       omap_cfg_reg(E19_24XX_MMC_DAT2);
+                       omap_cfg_reg(D19_24XX_MMC_DAT3);
+                       omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
+                       omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
+                       omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
+               }
+
+               /*
+                * Use internal loop-back in MMC/SDIO Module Input Clock
+                * selection
+                */
+               if (mmc_controller->slots[0].internal_clock) {
+                       u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
+                       v |= (1 << 24);
+                       omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
+               }
+       }
+}
+
+void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                       int nr_controllers)
+{
+       int i;
+
+       for (i = 0; i < nr_controllers; i++) {
+               unsigned long base, size;
+               unsigned int irq = 0;
+
+               if (!mmc_data[i])
+                       continue;
+
+               omap2_mmc_mux(mmc_data[i], i);
+
+               switch (i) {
+               case 0:
+                       base = OMAP2_MMC1_BASE;
+                       irq = INT_24XX_MMC_IRQ;
+                       break;
+               case 1:
+                       base = OMAP2_MMC2_BASE;
+                       irq = INT_24XX_MMC2_IRQ;
+                       break;
+               case 2:
+                       if (!cpu_is_omap34xx())
+                               return;
+                       base = OMAP3_MMC3_BASE;
+                       irq = INT_34XX_MMC3_IRQ;
+                       break;
+               default:
+                       continue;
+               }
+
+               if (cpu_is_omap2420())
+                       size = OMAP2420_MMC_SIZE;
+               else
+                       size = HSMMC_SIZE;
+
+               omap_mmc_add(i, base, size, irq, mmc_data[i]);
+       };
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#define OMAP_HDQ_BASE  0x480B2000
+#endif
+static struct resource omap_hdq_resources[] = {
+       {
+               .start          = OMAP_HDQ_BASE,
+               .end            = OMAP_HDQ_BASE + 0x1C,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = INT_24XX_HDQ_IRQ,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+static struct platform_device omap_hdq_dev = {
+       .name = "omap_hdq",
+       .id = 0,
+       .dev = {
+               .platform_data = NULL,
+       },
+       .num_resources  = ARRAY_SIZE(omap_hdq_resources),
+       .resource       = omap_hdq_resources,
+};
+static inline void omap_hdq_init(void)
+{
+       (void) platform_device_register(&omap_hdq_dev);
+}
+#else
+static inline void omap_hdq_init(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 static int __init omap2_init_devices(void)
@@ -208,10 +477,12 @@ static int __init omap2_init_devices(void)
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
-       omap_init_i2c();
+       omap_init_camera();
        omap_init_mbox();
        omap_init_mcspi();
+       omap_hdq_init();
        omap_init_sti();
+       omap_init_sha1_md5();
 
        return 0;
 }
index f51d69bc457dac2be97ff36c81ed4e037155c67c..f3e02712d8952831bb5636b6834660db17178530 100644 (file)
@@ -9,27 +9,23 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#undef DEBUG
+
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/ioport.h>
 #include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <mach/gpmc.h>
 
-#undef DEBUG
-
-#ifdef CONFIG_ARCH_OMAP2420
-#define GPMC_BASE              0x6800a000
-#endif
-
-#ifdef CONFIG_ARCH_OMAP2430
-#define GPMC_BASE              0x6E000000
-#endif
+#include <mach/sdrc.h>
 
+/* GPMC register offsets */
 #define GPMC_REVISION          0x00
 #define GPMC_SYSCONFIG         0x10
 #define GPMC_SYSSTATUS         0x14
@@ -51,7 +47,6 @@
 #define GPMC_CS0               0x60
 #define GPMC_CS_SIZE           0x30
 
-#define GPMC_CS_NUM            8
 #define GPMC_MEM_START         0x00000000
 #define GPMC_MEM_END           0x3FFFFFFF
 #define BOOT_ROM_SPACE         0x100000        /* 1MB */
@@ -64,12 +59,9 @@ static struct resource       gpmc_cs_mem[GPMC_CS_NUM];
 static DEFINE_SPINLOCK(gpmc_mem_lock);
 static unsigned                gpmc_cs_map;
 
-static void __iomem *gpmc_base =
-       (void __iomem *) IO_ADDRESS(GPMC_BASE);
-static void __iomem *gpmc_cs_base =
-       (void __iomem *) IO_ADDRESS(GPMC_BASE) + GPMC_CS0;
+static void __iomem *gpmc_base;
 
-static struct clk *gpmc_fck;
+static struct clk *gpmc_l3_clk;
 
 static void gpmc_write_reg(int idx, u32 val)
 {
@@ -85,19 +77,32 @@ void gpmc_cs_write_reg(int cs, int idx, u32 val)
 {
        void __iomem *reg_addr;
 
-       reg_addr = gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx;
+       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
        __raw_writel(val, reg_addr);
 }
 
 u32 gpmc_cs_read_reg(int cs, int idx)
 {
-       return __raw_readl(gpmc_cs_base + (cs * GPMC_CS_SIZE) + idx);
+       void __iomem *reg_addr;
+
+       reg_addr = gpmc_base + GPMC_CS0 + (cs * GPMC_CS_SIZE) + idx;
+       return __raw_readl(reg_addr);
 }
 
+/* TODO: Add support for gpmc_fck to clock framework and use it */
 unsigned long gpmc_get_fclk_period(void)
 {
-       /* In picoseconds */
-       return 1000000000 / ((clk_get_rate(gpmc_fck)) / 1000);
+       unsigned long rate = clk_get_rate(gpmc_l3_clk);
+
+       if (rate == 0) {
+               printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
+               return 0;
+       }
+
+       rate /= 1000;
+       rate = 1000000000 / rate;       /* In picoseconds */
+
+       return rate;
 }
 
 unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
@@ -110,6 +115,11 @@ unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
        return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_ticks_to_ns(unsigned int ticks)
+{
+       return ticks * gpmc_get_fclk_period() / 1000;
+}
+
 unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns)
 {
        unsigned long ticks = gpmc_ns_to_ticks(time_ns);
@@ -210,6 +220,11 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
 
        GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access);
 
+       if (cpu_is_omap34xx()) {
+               GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus);
+               GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
+       }
+
        /* caller is expected to have initialized CONFIG1 to cover
         * at least sync vs async
         */
@@ -350,6 +365,7 @@ out:
        spin_unlock(&gpmc_mem_lock);
        return r;
 }
+EXPORT_SYMBOL(gpmc_cs_request);
 
 void gpmc_cs_free(int cs)
 {
@@ -365,8 +381,9 @@ void gpmc_cs_free(int cs)
        gpmc_cs_set_reserved(cs, 0);
        spin_unlock(&gpmc_mem_lock);
 }
+EXPORT_SYMBOL(gpmc_cs_free);
 
-void __init gpmc_mem_init(void)
+static void __init gpmc_mem_init(void)
 {
        int cs;
        unsigned long boot_rom_space = 0;
@@ -396,12 +413,33 @@ void __init gpmc_mem_init(void)
 void __init gpmc_init(void)
 {
        u32 l;
+       char *ck;
+
+       if (cpu_is_omap24xx()) {
+               ck = "core_l3_ck";
+               if (cpu_is_omap2420())
+                       l = OMAP2420_GPMC_BASE;
+               else
+                       l = OMAP34XX_GPMC_BASE;
+       } else if (cpu_is_omap34xx()) {
+               ck = "gpmc_fck";
+               l = OMAP34XX_GPMC_BASE;
+       }
 
-       gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
-       if (IS_ERR(gpmc_fck))
-               WARN_ON(1);
-       else
-               clk_enable(gpmc_fck);
+       gpmc_l3_clk = clk_get(NULL, ck);
+       if (IS_ERR(gpmc_l3_clk)) {
+               printk(KERN_ERR "Could not get GPMC clock %s\n", ck);
+               return -ENODEV;
+       }
+
+       gpmc_base = ioremap(l, SZ_4K);
+       if (!gpmc_base) {
+               clk_put(gpmc_l3_clk);
+               printk(KERN_ERR "Could not get GPMC register memory\n");
+               return -ENOMEM;
+       }
+
+       BUG_ON(IS_ERR(gpmc_l3_clk));
 
        l = gpmc_read_reg(GPMC_REVISION);
        printk(KERN_INFO "GPMC revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
new file mode 100644 (file)
index 0000000..c6ff490
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * linux/arch/arm/mach-omap2/board-sdp-hsmmc.c
+ *
+ * Copyright (C) 2007-2008 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl4030.h>
+#include <mach/hardware.h>
+#include <mach/mmc.h>
+#include <mach/board.h>
+
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+
+#define VMMC1_DEV_GRP          0x27
+#define P1_DEV_GRP             0x20
+#define VMMC1_DEDICATED                0x2A
+#define VSEL_3V                        0x02
+#define VSEL_18V               0x00
+#define TWL_GPIO_IMR1A         0x1C
+#define TWL_GPIO_ISR1A         0x19
+#define LDO_CLR                        0x00
+#define VSEL_S2_CLR            0x40
+#define GPIO_0_BIT_POS         (1 << 0)
+#define MMC1_CD_IRQ            0
+#define MMC2_CD_IRQ            1
+
+#define OMAP2_CONTROL_DEVCONF0 0x48002274
+#define OMAP2_CONTROL_DEVCONF1 0x490022E8
+
+#define OMAP2_CONTROL_DEVCONF0_LBCLK   (1 << 24)
+#define OMAP2_CONTROL_DEVCONF1_ACTOV   (1 << 31)
+
+#define OMAP2_CONTROL_PBIAS_VMODE      (1 << 0)
+#define OMAP2_CONTROL_PBIAS_PWRDNZ     (1 << 1)
+#define OMAP2_CONTROL_PBIAS_SCTRL      (1 << 2)
+
+static int hsmmc_card_detect(int irq)
+{
+       return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
+}
+
+/*
+ * MMC Slot Initialization.
+ */
+static int hsmmc_late_init(struct device *dev)
+{
+       int ret = 0;
+
+       /*
+        * Configure TWL4030 GPIO parameters for MMC hotplug irq
+        */
+       ret = twl4030_request_gpio(MMC1_CD_IRQ);
+       if (ret)
+               goto err;
+
+       ret = twl4030_set_gpio_debounce(MMC1_CD_IRQ, TWL4030_GPIO_IS_ENABLE);
+       if (ret)
+               goto err;
+
+       return ret;
+
+err:
+       dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+       return ret;
+}
+
+static void hsmmc_cleanup(struct device *dev)
+{
+       int ret = 0;
+
+       ret = twl4030_free_gpio(MMC1_CD_IRQ);
+       if (ret)
+               dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * To mask and unmask MMC Card Detect Interrupt
+ * mask : 1
+ * unmask : 0
+ */
+static int mask_cd_interrupt(int mask)
+{
+       u8 reg = 0, ret = 0;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_IMR1A);
+       if (ret)
+               goto err;
+
+       reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_IMR1A);
+       if (ret)
+               goto err;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &reg, TWL_GPIO_ISR1A);
+       if (ret)
+               goto err;
+
+       reg = (mask == 1) ? (reg | GPIO_0_BIT_POS) : (reg & ~GPIO_0_BIT_POS);
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, reg, TWL_GPIO_ISR1A);
+       if (ret)
+               goto err;
+
+err:
+       return ret;
+}
+
+static int hsmmc_suspend(struct device *dev, int slot)
+{
+       int ret = 0;
+
+       disable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+       ret = mask_cd_interrupt(1);
+
+       return ret;
+}
+
+static int hsmmc_resume(struct device *dev, int slot)
+{
+       int ret = 0;
+
+       enable_irq(TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ));
+       ret = mask_cd_interrupt(0);
+
+       return ret;
+}
+
+#endif
+
+static int hsmmc_set_power(struct device *dev, int slot, int power_on,
+                               int vdd)
+{
+       u32 vdd_sel = 0, devconf = 0, reg = 0;
+       int ret = 0;
+
+       /* REVISIT: Using address directly till the control.h defines
+        * are settled.
+        */
+#if defined(CONFIG_ARCH_OMAP2430)
+       #define OMAP2_CONTROL_PBIAS 0x490024A0
+#else
+       #define OMAP2_CONTROL_PBIAS 0x48002520
+#endif
+
+       if (power_on) {
+               if (cpu_is_omap24xx())
+                       devconf = omap_readl(OMAP2_CONTROL_DEVCONF1);
+               else
+                       devconf = omap_readl(OMAP2_CONTROL_DEVCONF0);
+
+               switch (1 << vdd) {
+               case MMC_VDD_33_34:
+               case MMC_VDD_32_33:
+                       vdd_sel = VSEL_3V;
+                       if (cpu_is_omap24xx())
+                               devconf |= OMAP2_CONTROL_DEVCONF1_ACTOV;
+                       break;
+               case MMC_VDD_165_195:
+                       vdd_sel = VSEL_18V;
+                       if (cpu_is_omap24xx())
+                               devconf &= ~OMAP2_CONTROL_DEVCONF1_ACTOV;
+               }
+
+               if (cpu_is_omap24xx())
+                       omap_writel(devconf, OMAP2_CONTROL_DEVCONF1);
+               else
+                       omap_writel(devconf | OMAP2_CONTROL_DEVCONF0_LBCLK,
+                                   OMAP2_CONTROL_DEVCONF0);
+
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg |= OMAP2_CONTROL_PBIAS_SCTRL;
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               P1_DEV_GRP, VMMC1_DEV_GRP);
+               if (ret)
+                       goto err;
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               vdd_sel, VMMC1_DEDICATED);
+               if (ret)
+                       goto err;
+
+               msleep(100);
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg |= (OMAP2_CONTROL_PBIAS_SCTRL |
+                       OMAP2_CONTROL_PBIAS_PWRDNZ);
+               if (vdd_sel == VSEL_18V)
+                       reg &= ~OMAP2_CONTROL_PBIAS_VMODE;
+               else
+                       reg |= OMAP2_CONTROL_PBIAS_VMODE;
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+               return ret;
+
+       } else {
+               /* Power OFF */
+
+               /* For MMC1, Toggle PBIAS before every power up sequence */
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg &= ~OMAP2_CONTROL_PBIAS_PWRDNZ;
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               LDO_CLR, VMMC1_DEV_GRP);
+               if (ret)
+                       goto err;
+
+               ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                               VSEL_S2_CLR, VMMC1_DEDICATED);
+               if (ret)
+                       goto err;
+
+               /* 100ms delay required for PBIAS configuration */
+               msleep(100);
+               reg = omap_readl(OMAP2_CONTROL_PBIAS);
+               reg |= (OMAP2_CONTROL_PBIAS_VMODE |
+                       OMAP2_CONTROL_PBIAS_PWRDNZ |
+                       OMAP2_CONTROL_PBIAS_SCTRL);
+               omap_writel(reg, OMAP2_CONTROL_PBIAS);
+       }
+
+       return 0;
+
+err:
+       return 1;
+}
+
+static struct omap_mmc_platform_data mmc1_data = {
+       .nr_slots                       = 1,
+       .init                           = hsmmc_late_init,
+       .cleanup                        = hsmmc_cleanup,
+#ifdef CONFIG_PM
+       .suspend                        = hsmmc_suspend,
+       .resume                         = hsmmc_resume,
+#endif
+       .dma_mask                       = 0xffffffff,
+       .slots[0] = {
+               .wire4                  = 1,
+               .set_power              = hsmmc_set_power,
+               .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34 |
+                                               MMC_VDD_165_195,
+               .name                   = "first slot",
+
+               .card_detect_irq        = TWL4030_GPIO_IRQ_NO(MMC1_CD_IRQ),
+               .card_detect            = hsmmc_card_detect,
+       },
+};
+
+static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC];
+
+void __init hsmmc_init(void)
+{
+       hsmmc_data[0] = &mmc1_data;
+       omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC);
+}
+
+#else
+
+void __init hsmmc_init(void)
+{
+
+}
+
+#endif
index a5d4526ac4d6debdb1f0a0e0393bc37443e00bac..7a7ad186376db78c6e81d0bfee20eaf1b534c0af 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
-#include <asm/io.h>
-
+#include <mach/common.h>
 #include <mach/control.h>
 #include <mach/cpu.h>
 
-#if defined(CONFIG_ARCH_OMAP2420)
-#define TAP_BASE       io_p2v(0x48014000)
-#elif defined(CONFIG_ARCH_OMAP2430)
-#define TAP_BASE       io_p2v(0x4900A000)
-#elif defined(CONFIG_ARCH_OMAP34XX)
-#define TAP_BASE       io_p2v(0x4830A000)
-#endif
-
-#define OMAP_TAP_IDCODE                0x0204
-#if defined(CONFIG_ARCH_OMAP34XX)
-#define OMAP_TAP_PROD_ID       0x0210
-#else
-#define OMAP_TAP_PROD_ID       0x0208
-#endif
-
-#define OMAP_TAP_DIE_ID_0      0x0218
-#define OMAP_TAP_DIE_ID_1      0x021C
-#define OMAP_TAP_DIE_ID_2      0x0220
-#define OMAP_TAP_DIE_ID_3      0x0224
-
-/* system_rev fields for OMAP2 processors:
- *   CPU id bits     [31:16],
- *   CPU device type [15:12], (unprg,normal,POP)
- *   CPU revision    [11:08]
- *   CPU class bits  [07:00]
- */
-
-struct omap_id {
-       u16     hawkeye;        /* Silicon type (Hawkeye id) */
-       u8      dev;            /* Device type from production_id reg */
-       u32     type;           /* combined type id copied to system_rev */
-};
-
-/* Register values to detect the OMAP version */
-static struct omap_id omap_ids[] __initdata = {
-       { .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200000 },
-       { .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201000 },
-       { .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202000 },
-       { .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220000 },
-       { .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230000 },
-       { .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300000 },
-};
-
 static struct omap_chip_id omap_chip;
 
 /**
@@ -78,132 +35,66 @@ int omap_chip_is(struct omap_chip_id oci)
 }
 EXPORT_SYMBOL(omap_chip_is);
 
-static u32 __init read_tap_reg(int reg)
+int omap_type(void)
 {
-       unsigned int regval = 0;
-       u32 cpuid;
-
-       /* Reading the IDCODE register on 3430 ES1 results in a
-        * data abort as the register is not exposed on the OCP
-        * Hence reading the Cortex Rev
-        */
-       cpuid = read_cpuid(CPUID_ID);
-
-       /* If the processor type is Cortex-A8 and the revision is 0x0
-        * it means its Cortex r0p0 which is 3430 ES1
-        */
-       if ((((cpuid >> 4) & 0xFFF) == 0xC08) && ((cpuid & 0xF) == 0x0)) {
-               switch (reg) {
-               case OMAP_TAP_IDCODE  : regval = 0x0B7AE02F; break;
-               /* Making DevType as 0xF in ES1 to differ from ES2 */
-               case OMAP_TAP_PROD_ID : regval = 0x000F00F0; break;
-               case OMAP_TAP_DIE_ID_0: regval = 0x01000000; break;
-               case OMAP_TAP_DIE_ID_1: regval = 0x1012d687; break;
-               case OMAP_TAP_DIE_ID_2: regval = 0x00000000; break;
-               case OMAP_TAP_DIE_ID_3: regval = 0x2d2c0000; break;
-               }
-       } else
-               regval = __raw_readl(TAP_BASE + reg);
-
-       return regval;
-
-}
+       u32 val = 0;
 
-/*
- * _set_system_rev - set the system_rev global based on current OMAP chip type
- *
- * Set the system_rev global.  This is primarily used by the cpu_is_omapxxxx()
- * macros.
- */
-static void __init _set_system_rev(u32 type, u8 rev)
-{
-       u32 i, ctrl_status;
-
-       /*
-        * system_rev encoding is as follows
-        * system_rev & 0xff000000 -> Omap Class (24xx/34xx)
-        * system_rev & 0xfff00000 -> Omap Sub Class (242x/343x)
-        * system_rev & 0xffff0000 -> Omap type (2420/2422/2423/2430/3430)
-        * system_rev & 0x0000f000 -> Silicon revision (ES1, ES2 )
-        * system_rev & 0x00000700 -> Device Type ( EMU/HS/GP/BAD )
-        * system_rev & 0x000000c0 -> IDCODE revision[6:7]
-        * system_rev & 0x0000003f -> sys_boot[0:5]
-        */
-       /* Embedding the ES revision info in type field */
-       system_rev = type;
-       /* Also add IDCODE revision info only two lower bits */
-       system_rev |= ((rev & 0x3) << 6);
-
-       /* Add in the device type and sys_boot fields (see above) */
        if (cpu_is_omap24xx()) {
-               i = OMAP24XX_CONTROL_STATUS;
-       } else if (cpu_is_omap343x()) {
-               i = OMAP343X_CONTROL_STATUS;
+               val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
+       } else if (cpu_is_omap34xx()) {
+               val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
        } else {
-               printk(KERN_ERR "id: unknown CPU type\n");
-               BUG();
+               pr_err("Cannot detect omap type!\n");
+               goto out;
        }
-       ctrl_status = omap_ctrl_readl(i);
-       system_rev |= (ctrl_status & (OMAP2_SYSBOOT_5_MASK |
-                                     OMAP2_SYSBOOT_4_MASK |
-                                     OMAP2_SYSBOOT_3_MASK |
-                                     OMAP2_SYSBOOT_2_MASK |
-                                     OMAP2_SYSBOOT_1_MASK |
-                                     OMAP2_SYSBOOT_0_MASK));
-       system_rev |= (ctrl_status & OMAP2_DEVICETYPE_MASK);
-}
-
-
-/*
- * _set_omap_chip - set the omap_chip global based on OMAP chip type
- *
- * Build the omap_chip bits.  This variable is used by powerdomain and
- * clockdomain code to indicate whether structures are applicable for
- * the current OMAP chip type by ANDing it against a 'platform' bitfield
- * in the structure.
- */
-static void __init _set_omap_chip(void)
-{
-       if (cpu_is_omap343x()) {
 
-               omap_chip.oc = CHIP_IS_OMAP3430;
-               if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0))
-                       omap_chip.oc |= CHIP_IS_OMAP3430ES1;
-               else if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0))
-                       omap_chip.oc |= CHIP_IS_OMAP3430ES2;
+       val &= OMAP2_DEVICETYPE_MASK;
+       val >>= 8;
 
-       } else if (cpu_is_omap243x()) {
+out:
+       return val;
+}
+EXPORT_SYMBOL(omap_type);
 
-               /* Currently only supports 2430ES2.1 and 2430-all */
-               omap_chip.oc |= CHIP_IS_OMAP2430;
 
-       } else if (cpu_is_omap242x()) {
+/*----------------------------------------------------------------------------*/
 
-               /* Currently only supports 2420ES2.1.1 and 2420-all */
-               omap_chip.oc |= CHIP_IS_OMAP2420;
+#define OMAP_TAP_IDCODE                0x0204
+#define OMAP_TAP_DIE_ID_0      0x0218
+#define OMAP_TAP_DIE_ID_1      0x021C
+#define OMAP_TAP_DIE_ID_2      0x0220
+#define OMAP_TAP_DIE_ID_3      0x0224
 
-       } else {
+#define read_tap_reg(reg)      __raw_readl(tap_base  + (reg))
 
-               /* Current CPU not supported by this code. */
-               printk(KERN_WARNING "OMAP chip type code does not yet support "
-                      "this CPU type.\n");
-               WARN_ON(1);
+struct omap_id {
+       u16     hawkeye;        /* Silicon type (Hawkeye id) */
+       u8      dev;            /* Device type from production_id reg */
+       u32     type;           /* Combined type id copied to system_rev */
+};
 
-       }
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+       { .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200024 },
+       { .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201024 },
+       { .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202024 },
+       { .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220024 },
+       { .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230024 },
+       { .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300024 },
+};
 
-}
+static void __iomem *tap_base;
+static u16 tap_prod_id;
 
-void __init omap2_check_revision(void)
+void __init omap24xx_check_revision(void)
 {
        int i, j;
-       u32 idcode;
-       u32 prod_id;
+       u32 idcode, prod_id;
        u16 hawkeye;
-       u8  dev_type;
-       u8  rev;
+       u8  dev_type, rev;
 
        idcode = read_tap_reg(OMAP_TAP_IDCODE);
-       prod_id = read_tap_reg(OMAP_TAP_PROD_ID);
+       prod_id = read_tap_reg(tap_prod_id);
        hawkeye = (idcode >> 12) & 0xffff;
        rev = (idcode >> 28) & 0x0f;
        dev_type = (prod_id >> 16) & 0x0f;
@@ -222,18 +113,6 @@ void __init omap2_check_revision(void)
        pr_debug("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n",
                 prod_id, dev_type);
 
-       /*
-        * Detection for 34xx ES2.0 and above can be done with just
-        * hawkeye and rev. See TRM 1.5.2 Device Identification.
-        * Note that rev cannot be used directly as ES1.0 uses value 0.
-        */
-       if (hawkeye == 0xb7ae) {
-               system_rev = 0x34300000 | ((1 + rev) << 12);
-               pr_info("OMAP%04x ES2.%i\n", system_rev >> 16, rev);
-               _set_omap_chip();
-               return;
-       }
-
        /* Check hawkeye ids */
        for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
                if (hawkeye == omap_ids[i].hawkeye)
@@ -257,14 +136,117 @@ void __init omap2_check_revision(void)
                j = i;
        }
 
-       _set_system_rev(omap_ids[j].type, rev);
-
-       _set_omap_chip();
-
        pr_info("OMAP%04x", system_rev >> 16);
        if ((system_rev >> 8) & 0x0f)
                pr_info("ES%x", (system_rev >> 12) & 0xf);
        pr_info("\n");
+}
 
+void __init omap34xx_check_revision(void)
+{
+       u32 cpuid, idcode;
+       u16 hawkeye;
+       u8 rev;
+       char *rev_name;
+
+       /*
+        * We cannot access revision registers on ES1.0.
+        * If the processor type is Cortex-A8 and the revision is 0x0
+        * it means its Cortex r0p0 which is 3430 ES1.0.
+        */
+       cpuid = read_cpuid(CPUID_ID);
+       if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
+               system_rev = OMAP3430_REV_ES1_0;
+               rev_name = "ES1.0";
+               goto out;
+       }
+
+       /*
+        * Detection for 34xx ES2.0 and above can be done with just
+        * hawkeye and rev. See TRM 1.5.2 Device Identification.
+        * Note that rev does not map directly to our defined processor
+        * revision numbers as ES1.0 uses value 0.
+        */
+       idcode = read_tap_reg(OMAP_TAP_IDCODE);
+       hawkeye = (idcode >> 12) & 0xffff;
+       rev = (idcode >> 28) & 0xff;
+
+       if (hawkeye == 0xb7ae) {
+               switch (rev) {
+               case 0:
+                       system_rev = OMAP3430_REV_ES2_0;
+                       rev_name = "ES2.0";
+                       break;
+               case 2:
+                       system_rev = OMAP3430_REV_ES2_1;
+                       rev_name = "ES2.1";
+                       break;
+               case 3:
+                       system_rev = OMAP3430_REV_ES3_0;
+                       rev_name = "ES3.0";
+                       break;
+               default:
+                       /* Use the latest known revision as default */
+                       system_rev = OMAP3430_REV_ES3_0;
+                       rev_name = "Unknown revision\n";
+               }
+       }
+
+out:
+       pr_info("OMAP%04x %s\n", system_rev >> 16, rev_name);
+}
+
+/*
+ * Try to detect the exact revision of the omap we're running on
+ */
+void __init omap2_check_revision(void)
+{
+       /*
+        * At this point we have an idea about the processor revision set
+        * earlier with omap2_set_globals_tap().
+        */
+       if (cpu_is_omap24xx())
+               omap24xx_check_revision();
+       else if (cpu_is_omap34xx())
+               omap34xx_check_revision();
+       else
+               pr_err("OMAP revision unknown, please fix!\n");
+
+       /*
+        * OK, now we know the exact revision. Initialize omap_chip bits
+        * for powerdowmain and clockdomain code.
+        */
+       if (cpu_is_omap243x()) {
+               /* Currently only supports 2430ES2.1 and 2430-all */
+               omap_chip.oc |= CHIP_IS_OMAP2430;
+       } else if (cpu_is_omap242x()) {
+               /* Currently only supports 2420ES2.1.1 and 2420-all */
+               omap_chip.oc |= CHIP_IS_OMAP2420;
+       } else if (cpu_is_omap343x()) {
+               omap_chip.oc = CHIP_IS_OMAP3430;
+               if (system_rev == OMAP3430_REV_ES1_0)
+                       omap_chip.oc |= CHIP_IS_OMAP3430ES1;
+               else if (system_rev > OMAP3430_REV_ES1_0)
+                       omap_chip.oc |= CHIP_IS_OMAP3430ES2;
+       } else {
+               pr_err("Uninitialized omap_chip, please fix!\n");
+       }
 }
 
+/*
+ * Set up things for map_io and processor detection later on. Gets called
+ * pretty much first thing from board init. For multi-omap, this gets
+ * cpu_is_omapxxxx() working accurately enough for map_io. Then we'll try to
+ * detect the exact revision later on in omap2_detect_revision() once map_io
+ * is done.
+ */
+void __init omap2_set_globals_tap(struct omap_globals *omap2_globals)
+{
+       system_rev = omap2_globals->class;
+       tap_base = omap2_globals->tap;
+
+       if (cpu_is_omap34xx())
+               tap_prod_id = 0x0210;
+       else
+               tap_prod_id = 0x0208;
+}
index 987351f07d7b618bb0a10ea12a2d18001a9415e4..adbe21fcd68408c30b712d06aff6daf671afed38 100644 (file)
@@ -4,8 +4,11 @@
  * OMAP2 I/O mapping code
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
- * Updated map desc to add 2430 support : <x0khasim@ti.com>
+ * Copyright (C) 2007 Texas Instruments
+ *
+ * Author:
+ *     Juha Yrjola <juha.yrjola@nokia.com>
+ *     Syed Khasim <x0khasim@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 
 #include <asm/tlb.h>
-#include <asm/io.h>
 
 #include <asm/mach/map.h>
-
 #include <mach/mux.h>
 #include <mach/omapfb.h>
+#include <mach/sram.h>
+#include <mach/sdrc.h>
+#include <mach/gpmc.h>
+
+#include "clock.h"
+
+#include <mach/powerdomain.h>
+
+#include "powerdomains.h"
 
-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);
-extern void omapfb_reserve_sdram(void);
+#include <mach/clockdomain.h>
+#include "clockdomains.h"
 
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
  */
-static struct map_desc omap2_io_desc[] __initdata = {
+
+#ifdef CONFIG_ARCH_OMAP24XX
+static struct map_desc omap24xx_io_desc[] __initdata = {
        {
                .virtual        = L3_24XX_VIRT,
                .pfn            = __phys_to_pfn(L3_24XX_PHYS),
@@ -43,12 +52,39 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .type           = MT_DEVICE
        },
        {
-               .virtual        = L4_24XX_VIRT,
-               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
-               .length         = L4_24XX_SIZE,
-               .type           = MT_DEVICE
+               .virtual        = L4_24XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_24XX_PHYS),
+               .length         = L4_24XX_SIZE,
+               .type           = MT_DEVICE
        },
+};
+
+#ifdef CONFIG_ARCH_OMAP2420
+static struct map_desc omap242x_io_desc[] __initdata = {
+       {
+               .virtual        = DSP_MEM_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+               .length         = DSP_MEM_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_IPI_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+               .length         = DSP_IPI_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = DSP_MMU_24XX_VIRT,
+               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+               .length         = DSP_MMU_24XX_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+
+#endif
+
 #ifdef CONFIG_ARCH_OMAP2430
+static struct map_desc omap243x_io_desc[] __initdata = {
        {
                .virtual        = L4_WK_243X_VIRT,
                .pfn            = __phys_to_pfn(L4_WK_243X_PHYS),
@@ -61,30 +97,90 @@ static struct map_desc omap2_io_desc[] __initdata = {
                .length         = OMAP243X_GPMC_SIZE,
                .type           = MT_DEVICE
        },
+       {
+               .virtual        = OMAP243X_SDRC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP243X_SDRC_PHYS),
+               .length         = OMAP243X_SDRC_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP243X_SMS_VIRT,
+               .pfn            = __phys_to_pfn(OMAP243X_SMS_PHYS),
+               .length         = OMAP243X_SMS_SIZE,
+               .type           = MT_DEVICE
+       },
+};
+#endif
 #endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct map_desc omap34xx_io_desc[] __initdata = {
        {
-               .virtual        = DSP_MEM_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_MEM_24XX_PHYS),
-               .length         = DSP_MEM_24XX_SIZE,
+               .virtual        = L3_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L3_34XX_PHYS),
+               .length         = L3_34XX_SIZE,
                .type           = MT_DEVICE
        },
        {
-               .virtual        = DSP_IPI_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_IPI_24XX_PHYS),
-               .length         = DSP_IPI_24XX_SIZE,
+               .virtual        = L4_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_34XX_PHYS),
+               .length         = L4_34XX_SIZE,
                .type           = MT_DEVICE
        },
        {
-               .virtual        = DSP_MMU_24XX_VIRT,
-               .pfn            = __phys_to_pfn(DSP_MMU_24XX_PHYS),
-               .length         = DSP_MMU_24XX_SIZE,
+               .virtual        = L4_WK_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_WK_34XX_PHYS),
+               .length         = L4_WK_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP34XX_GPMC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP34XX_GPMC_PHYS),
+               .length         = OMAP34XX_GPMC_SIZE,
                .type           = MT_DEVICE
-       }
+       },
+       {
+               .virtual        = OMAP343X_SMS_VIRT,
+               .pfn            = __phys_to_pfn(OMAP343X_SMS_PHYS),
+               .length         = OMAP343X_SMS_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = OMAP343X_SDRC_VIRT,
+               .pfn            = __phys_to_pfn(OMAP343X_SDRC_PHYS),
+               .length         = OMAP343X_SDRC_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = L4_PER_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_PER_34XX_PHYS),
+               .length         = L4_PER_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
+       {
+               .virtual        = L4_EMU_34XX_VIRT,
+               .pfn            = __phys_to_pfn(L4_EMU_34XX_PHYS),
+               .length         = L4_EMU_34XX_SIZE,
+               .type           = MT_DEVICE
+       },
 };
+#endif
 
 void __init omap2_map_common_io(void)
 {
-       iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc));
+#if defined(CONFIG_ARCH_OMAP2420)
+       iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+       iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2430)
+       iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
+       iotable_init(omap243x_io_desc, ARRAY_SIZE(omap243x_io_desc));
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+       iotable_init(omap34xx_io_desc, ARRAY_SIZE(omap34xx_io_desc));
+#endif
 
        /* Normally devicemaps_init() would flush caches and tlb after
         * mdesc->map_io(), but we must also do it here because of the CPU
@@ -98,15 +194,12 @@ void __init omap2_map_common_io(void)
        omapfb_reserve_sdram();
 }
 
-void __init omap2_init_common_hw(void)
+void __init omap2_init_common_hw(struct omap_sdrc_params *sp)
 {
        omap2_mux_init();
+       pwrdm_init(powerdomains_omap);
+       clkdm_init(clockdomains_omap, clkdm_pwrdm_autodeps);
        omap2_clk_init();
-/*
- * Need to Fix this for 2430
- */
-#ifndef CONFIG_ARCH_OMAP2430
-       omap2_init_memory();
-#endif
+       omap2_sdrc_init(sp);
        gpmc_init();
 }
index 9ef15b31d8fcc4f8c0b62167ef889685905fcbd1..598392649cd28daf3c46894fc22dcd11621aa55b 100644 (file)
 #include <linux/interrupt.h>
 #include <mach/hardware.h>
 #include <asm/mach/irq.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 
-#define INTC_REVISION  0x0000
-#define INTC_SYSCONFIG 0x0010
-#define INTC_SYSSTATUS 0x0014
-#define INTC_CONTROL   0x0048
-#define INTC_MIR_CLEAR0        0x0088
-#define INTC_MIR_SET0  0x008c
+/* selected INTC register offsets */
+
+#define INTC_REVISION          0x0000
+#define INTC_SYSCONFIG         0x0010
+#define INTC_SYSSTATUS         0x0014
+#define INTC_CONTROL           0x0048
+#define INTC_MIR_CLEAR0                0x0088
+#define INTC_MIR_SET0          0x008c
+#define INTC_PENDING_IRQ0      0x0098
+
+/* Number of IRQ state bits in each MIR register */
+#define IRQ_BITS_PER_REG       32
 
 /*
  * OMAP2 has a number of different interrupt controllers, each interrupt
  * for each bank.. when in doubt, consult the TRM.
  */
 static struct omap_irq_bank {
-       unsigned long base_reg;
+       void __iomem *base_reg;
        unsigned int nr_irqs;
 } __attribute__ ((aligned(4))) irq_banks[] = {
        {
                /* MPU INTC */
-               .base_reg       = IO_ADDRESS(OMAP24XX_IC_BASE),
+               .base_reg       = 0,
                .nr_irqs        = 96,
-       }, {
-               /* XXX: DSP INTC */
-       }
+       },
 };
 
+/* INTC bank register get/set */
+
+static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg)
+{
+       __raw_writel(val, (__force void __iomem *)(bank->base_reg + reg));
+}
+
+static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
+{
+       return __raw_readl((__force void __iomem *)(bank->base_reg + reg));
+}
+
 /* XXX: FIQ and additional INTC support (only MPU at the moment) */
 static void omap_ack_irq(unsigned int irq)
 {
-       __raw_writel(0x1, irq_banks[0].base_reg + INTC_CONTROL);
+       intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
 }
 
 static void omap_mask_irq(unsigned int irq)
 {
-       int offset = (irq >> 5) << 5;
+       int offset = irq & (~(IRQ_BITS_PER_REG - 1));
 
-       if (irq >= 64) {
-               irq %= 64;
-       } else if (irq >= 32) {
-               irq %= 32;
-       }
+       irq &= (IRQ_BITS_PER_REG - 1);
 
-       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_SET0 + offset);
+       intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
 }
 
 static void omap_unmask_irq(unsigned int irq)
 {
-       int offset = (irq >> 5) << 5;
+       int offset = irq & (~(IRQ_BITS_PER_REG - 1));
 
-       if (irq >= 64) {
-               irq %= 64;
-       } else if (irq >= 32) {
-               irq %= 32;
-       }
+       irq &= (IRQ_BITS_PER_REG - 1);
 
-       __raw_writel(1 << irq, irq_banks[0].base_reg + INTC_MIR_CLEAR0 + offset);
+       intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
 }
 
 static void omap_mask_ack_irq(unsigned int irq)
@@ -93,20 +100,40 @@ static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
 {
        unsigned long tmp;
 
-       tmp = __raw_readl(bank->base_reg + INTC_REVISION) & 0xff;
-       printk(KERN_INFO "IRQ: Found an INTC at 0x%08lx "
+       tmp = intc_bank_read_reg(bank, INTC_REVISION) & 0xff;
+       printk(KERN_INFO "IRQ: Found an INTC at 0x%p "
                         "(revision %ld.%ld) with %d interrupts\n",
                         bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
 
-       tmp = __raw_readl(bank->base_reg + INTC_SYSCONFIG);
+       tmp = intc_bank_read_reg(bank, INTC_SYSCONFIG);
        tmp |= 1 << 1;  /* soft reset */
-       __raw_writel(tmp, bank->base_reg + INTC_SYSCONFIG);
+       intc_bank_write_reg(tmp, bank, INTC_SYSCONFIG);
 
-       while (!(__raw_readl(bank->base_reg + INTC_SYSSTATUS) & 0x1))
+       while (!(intc_bank_read_reg(bank, INTC_SYSSTATUS) & 0x1))
                /* Wait for reset to complete */;
 
        /* Enable autoidle */
-       __raw_writel(1 << 0, bank->base_reg + INTC_SYSCONFIG);
+       intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
+}
+
+int omap_irq_pending(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
+               struct omap_irq_bank *bank = irq_banks + i;
+               int irq;
+
+               for (irq = 0; irq < bank->nr_irqs; irq += IRQ_BITS_PER_REG) {
+                       int offset = irq & (~(IRQ_BITS_PER_REG - 1));
+
+                       if (intc_bank_read_reg(bank, (INTC_PENDING_IRQ0 +
+                                                     offset)))
+                               return 1;
+               }
+       }
+
+       return 0;
 }
 
 void __init omap_init_irq(void)
@@ -118,9 +145,10 @@ void __init omap_init_irq(void)
        for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
                struct omap_irq_bank *bank = irq_banks + i;
 
-               /* XXX */
-               if (!bank->base_reg)
-                       continue;
+               if (cpu_is_omap24xx())
+                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP24XX_IC_BASE);
+               else if (cpu_is_omap34xx())
+                       bank->base_reg = OMAP2_IO_ADDRESS(OMAP34XX_IC_BASE);
 
                omap_irq_bank_init_one(bank);
 
index a480b96948e48ad66b50a1ba6798983c2890d2eb..6e198d00fa3303211b033f84b11a985ada1f73fd 100644 (file)
@@ -75,12 +75,12 @@ static void omap2_mbox_enable_irq(struct omap_mbox *mbox,
 
 static inline unsigned int mbox_read_reg(unsigned int reg)
 {
-       return __raw_readl(mbox_base + reg);
+       return __raw_readl((void __iomem *)(mbox_base + reg));
 }
 
 static inline void mbox_write_reg(unsigned int val, unsigned int reg)
 {
-       __raw_writel(val, mbox_base + reg);
+       __raw_writel(val, (void __iomem *)(mbox_base + reg));
 }
 
 /* Mailbox H/W preparations */
index b261f1f80b5e0fd7131a5586ca04bb6d9796a3ea..cae3ebe249b3cdbacb18ece2b34e06aba82d17d5 100644 (file)
@@ -89,6 +89,30 @@ static struct mcbsp_internal_clk omap_mcbsp_clks[] = {
                        .disable        = omap_mcbsp_clk_disable,
                },
        },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 3,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 4,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
+       {
+               .clk = {
+                       .name           = "mcbsp_clk",
+                       .id             = 5,
+                       .enable         = omap_mcbsp_clk_enable,
+                       .disable        = omap_mcbsp_clk_disable,
+               },
+       },
 };
 
 #define omap_mcbsp_clks_size   ARRAY_SIZE(omap_mcbsp_clks)
@@ -117,25 +141,14 @@ static void omap2_mcbsp_request(unsigned int id)
                omap2_mcbsp2_mux_setup();
 }
 
-static int omap2_mcbsp_check(unsigned int id)
-{
-       if (id > OMAP_MAX_MCBSP_COUNT - 1) {
-               printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
-               return -ENODEV;
-       }
-       return 0;
-}
-
 static struct omap_mcbsp_ops omap2_mcbsp_ops = {
        .request        = omap2_mcbsp_request,
-       .check          = omap2_mcbsp_check,
 };
 
-#ifdef CONFIG_ARCH_OMAP24XX
-static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
+#ifdef CONFIG_ARCH_OMAP2420
+static struct omap_mcbsp_platform_data omap2420_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP24XX_MCBSP1_BASE,
-               .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
@@ -145,7 +158,6 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP24XX_MCBSP2_BASE,
-               .virt_base      = IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
@@ -154,17 +166,70 @@ static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
                .clk_name       = "mcbsp_clk",
        },
 };
-#define OMAP24XX_MCBSP_PDATA_SZ                ARRAY_SIZE(omap24xx_mcbsp_pdata)
+#define OMAP2420_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2420_mcbsp_pdata)
 #else
-#define omap24xx_mcbsp_pdata           NULL
-#define OMAP24XX_MCBSP_PDATA_SZ                0
+#define omap2420_mcbsp_pdata           NULL
+#define OMAP2420_MCBSP_PDATA_SZ                0
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+static struct omap_mcbsp_platform_data omap2430_mcbsp_pdata[] = {
+       {
+               .phys_base      = OMAP24XX_MCBSP1_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
+               .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP1_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP24XX_MCBSP2_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
+               .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP2_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP3_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
+               .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP4_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
+               .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP2430_MCBSP5_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
+               .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+};
+#define OMAP2430_MCBSP_PDATA_SZ                ARRAY_SIZE(omap2430_mcbsp_pdata)
+#else
+#define omap2430_mcbsp_pdata           NULL
+#define OMAP2430_MCBSP_PDATA_SZ                0
 #endif
 
 #ifdef CONFIG_ARCH_OMAP34XX
 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
        {
                .phys_base      = OMAP34XX_MCBSP1_BASE,
-               .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP1_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP1_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP1_TX,
                .rx_irq         = INT_24XX_MCBSP1_IRQ_RX,
@@ -174,7 +239,6 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
        },
        {
                .phys_base      = OMAP34XX_MCBSP2_BASE,
-               .virt_base      = IO_ADDRESS(OMAP34XX_MCBSP2_BASE),
                .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
                .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
                .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
@@ -182,6 +246,33 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
                .ops            = &omap2_mcbsp_ops,
                .clk_name       = "mcbsp_clk",
        },
+       {
+               .phys_base      = OMAP34XX_MCBSP3_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
+               .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP3_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP34XX_MCBSP4_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP4_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP4_TX,
+               .rx_irq         = INT_24XX_MCBSP4_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP4_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
+       {
+               .phys_base      = OMAP34XX_MCBSP5_BASE,
+               .dma_rx_sync    = OMAP24XX_DMA_MCBSP5_RX,
+               .dma_tx_sync    = OMAP24XX_DMA_MCBSP5_TX,
+               .rx_irq         = INT_24XX_MCBSP5_IRQ_RX,
+               .tx_irq         = INT_24XX_MCBSP5_IRQ_TX,
+               .ops            = &omap2_mcbsp_ops,
+               .clk_name       = "mcbsp_clk",
+       },
 };
 #define OMAP34XX_MCBSP_PDATA_SZ                ARRAY_SIZE(omap34xx_mcbsp_pdata)
 #else
@@ -189,7 +280,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 #define OMAP34XX_MCBSP_PDATA_SZ                0
 #endif
 
-int __init omap2_mcbsp_init(void)
+static int __init omap2_mcbsp_init(void)
 {
        int i;
 
@@ -199,10 +290,24 @@ int __init omap2_mcbsp_init(void)
                clk_register(&omap_mcbsp_clks[i].clk);
        }
 
-       if (cpu_is_omap24xx())
-               omap_mcbsp_register_board_cfg(omap24xx_mcbsp_pdata,
-                                               OMAP24XX_MCBSP_PDATA_SZ);
+       if (cpu_is_omap2420())
+               omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ;
+       if (cpu_is_omap2430())
+               omap_mcbsp_count = OMAP2430_MCBSP_PDATA_SZ;
+       if (cpu_is_omap34xx())
+               omap_mcbsp_count = OMAP34XX_MCBSP_PDATA_SZ;
+
+       mcbsp_ptr = kzalloc(omap_mcbsp_count * sizeof(struct omap_mcbsp *),
+                                                               GFP_KERNEL);
+       if (!mcbsp_ptr)
+               return -ENOMEM;
 
+       if (cpu_is_omap2420())
+               omap_mcbsp_register_board_cfg(omap2420_mcbsp_pdata,
+                                               OMAP2420_MCBSP_PDATA_SZ);
+       if (cpu_is_omap2430())
+               omap_mcbsp_register_board_cfg(omap2430_mcbsp_pdata,
+                                               OMAP2430_MCBSP_PDATA_SZ);
        if (cpu_is_omap34xx())
                omap_mcbsp_register_board_cfg(omap34xx_mcbsp_pdata,
                                                OMAP34XX_MCBSP_PDATA_SZ);
diff --git a/arch/arm/mach-omap2/memory.h b/arch/arm/mach-omap2/memory.h
deleted file mode 100644 (file)
index 9a280b5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/memory.h
- *
- * Interface for memory timing related functions for OMAP24XX
- *
- * Copyright (C) 2005 Texas Instruments Inc.
- * Richard Woodruff <r-woodruff2@ti.com>
- *
- * Copyright (C) 2005 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* Memory timings */
-#define M_DDR          1
-#define M_LOCK_CTRL    (1 << 2)
-#define M_UNLOCK       0
-#define M_LOCK         1
-
-struct memory_timings {
-       u32 m_type;             /* ddr = 1, sdr = 0 */
-       u32 dll_mode;           /* use lock mode = 1, unlock mode = 0 */
-       u32 slow_dll_ctrl;      /* unlock mode, dll value for slow speed */
-       u32 fast_dll_ctrl;      /* unlock mode, dll value for fast speed */
-       u32 base_cs;            /* base chip select to use for calculations */
-};
-
-extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode);
-extern u32 omap2_memory_get_slow_dll_ctrl(void);
-extern u32 omap2_memory_get_fast_dll_ctrl(void);
-extern u32 omap2_memory_get_type(void);
-u32 omap2_dll_force_needed(void);
-u32 omap2_reprogram_sdrc(u32 level, u32 force);
diff --git a/arch/arm/mach-omap2/mmu.c b/arch/arm/mach-omap2/mmu.c
new file mode 100644 (file)
index 0000000..6fc3303
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * linux/arch/arm/mach-omap2/mmu.c
+ *
+ * Support for non-MPU OMAP2 MMUs.
+ *
+ * Copyright (C) 2002-2007 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *        and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include "mmu.h"
+#include <mach/mmu.h>
+#include <asm/tlbflush.h>
+#include <asm/sizes.h>
+
+static void *dspvect_page;
+#define DSP_INIT_PAGE  0xfff000
+
+static inline void
+omap2_mmu_read_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       cr->cam = omap_mmu_read_reg(mmu, OMAP_MMU_READ_CAM);
+       cr->ram = omap_mmu_read_reg(mmu, OMAP_MMU_READ_RAM);
+}
+
+static inline void
+omap2_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       /* Set the CAM and RAM entries */
+       omap_mmu_write_reg(mmu, cr->cam | OMAP_MMU_CAM_V, OMAP_MMU_CAM);
+       omap_mmu_write_reg(mmu, cr->ram, OMAP_MMU_RAM);
+}
+
+static void exmap_setup_iomap_page(struct omap_mmu *mmu, unsigned long phys,
+                                  unsigned long dsp_io_adr, int index)
+{
+       unsigned long dspadr;
+       void *virt;
+       struct omap_mmu_tlb_entry tlb_ent;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = omap_mmu_to_virt(mmu, dspadr);
+       exmap_set_armmmu(mmu, (unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, NULL, virt);
+       INIT_TLB_ENTRY_4KB_ES32_PRESERVED(&tlb_ent, dspadr, phys);
+       omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+
+static void exmap_clear_iomap_page(struct omap_mmu *mmu,
+                                  unsigned long dsp_io_adr)
+{
+       unsigned long dspadr;
+       void *virt;
+
+       dspadr = (IOMAP_VAL << 18) + (dsp_io_adr << 1);
+       virt = omap_mmu_to_virt(mmu, dspadr);
+       exmap_clear_armmmu(mmu, (unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+
+#define OMAP24XX_MAILBOX_BASE  (L4_24XX_BASE + 0x94000)
+#define OMAP2420_GPT5_BASE     (L4_24XX_BASE + 0x7c000)
+#define OMAP2420_GPT6_BASE     (L4_24XX_BASE + 0x7e000)
+#define OMAP2420_GPT7_BASE     (L4_24XX_BASE + 0x80000)
+#define OMAP2420_GPT8_BASE     (L4_24XX_BASE + 0x82000)
+#define OMAP24XX_EAC_BASE      (L4_24XX_BASE + 0x90000)
+#define OMAP24XX_STI_BASE      (L4_24XX_BASE + 0x68000)
+#define OMAP24XX_STI_CH_BASE   (L4_24XX_BASE + 0x0c000000)
+
+static int exmap_setup_preserved_entries(struct omap_mmu *mmu)
+{
+       int i, n = 0;
+
+       exmap_setup_preserved_mem_page(mmu, dspvect_page, DSP_INIT_PAGE, n++);
+
+       /* REVISIT: This will need to be revisited for 3430 */
+       exmap_setup_iomap_page(mmu, OMAP2_PRCM_BASE, 0x7000, n++);
+       exmap_setup_iomap_page(mmu, OMAP24XX_MAILBOX_BASE, 0x11000, n++);
+
+       if (cpu_is_omap2420()) {
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT5_BASE, 0xe000, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT6_BASE, 0xe800, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT7_BASE, 0xf000, n++);
+               exmap_setup_iomap_page(mmu, OMAP2420_GPT8_BASE, 0xf800, n++);
+               exmap_setup_iomap_page(mmu, OMAP24XX_EAC_BASE,  0x10000, n++);
+               exmap_setup_iomap_page(mmu, OMAP24XX_STI_BASE, 0xc800, n++);
+               for (i = 0; i < 5; i++)
+                       exmap_setup_preserved_mem_page(mmu,
+                               __va(OMAP24XX_STI_CH_BASE + i*SZ_4K),
+                               0xfb0000 + i*SZ_4K, n++);
+       }
+
+       return n;
+}
+
+static void exmap_clear_preserved_entries(struct omap_mmu *mmu)
+{
+       int i;
+
+       exmap_clear_iomap_page(mmu, 0x7000);    /* PRCM registers */
+       exmap_clear_iomap_page(mmu, 0x11000);   /* MAILBOX registers */
+
+       if (cpu_is_omap2420()) {
+               exmap_clear_iomap_page(mmu, 0xe000);    /* GPT5 */
+               exmap_clear_iomap_page(mmu, 0xe800);    /* GPT6 */
+               exmap_clear_iomap_page(mmu, 0xf000);    /* GPT7 */
+               exmap_clear_iomap_page(mmu, 0xf800);    /* GPT8 */
+               exmap_clear_iomap_page(mmu, 0x10000);   /* EAC */
+               exmap_clear_iomap_page(mmu, 0xc800);    /* STI */
+               for (i = 0; i < 5; i++)                 /* STI CH */
+                       exmap_clear_mem_page(mmu, 0xfb0000 + i*SZ_4K);
+       }
+
+       exmap_clear_mem_page(mmu, DSP_INIT_PAGE);
+}
+
+#define MMU_IRQ_MASK \
+       (OMAP_MMU_IRQ_MULTIHITFAULT | \
+        OMAP_MMU_IRQ_TABLEWALKFAULT | \
+        OMAP_MMU_IRQ_EMUMISS | \
+        OMAP_MMU_IRQ_TRANSLATIONFAULT)
+
+static int omap2_mmu_startup(struct omap_mmu *mmu)
+{
+       u32 rev = omap_mmu_read_reg(mmu, OMAP_MMU_REVISION);
+
+       pr_info("MMU: OMAP %s MMU initialized (HW v%d.%d)\n", mmu->name,
+               (rev >> 4) & 0xf, rev & 0xf);
+
+       dspvect_page = (void *)__get_dma_pages(GFP_KERNEL, 0);
+       if (dspvect_page == NULL) {
+               dev_err(mmu->dev, "MMU %s: failed to allocate memory "
+                       "for vector table\n", mmu->name);
+               return -ENOMEM;
+       }
+
+       mmu->nr_exmap_preserved = exmap_setup_preserved_entries(mmu);
+
+       omap_mmu_write_reg(mmu, MMU_IRQ_MASK, OMAP_MMU_IRQENABLE);
+
+       return 0;
+}
+
+static void omap2_mmu_shutdown(struct omap_mmu *mmu)
+{
+       exmap_clear_preserved_entries(mmu);
+
+       if (dspvect_page != NULL) {
+               unsigned long virt;
+
+               down_read(&mmu->exmap_sem);
+
+               virt = (unsigned long)omap_mmu_to_virt(mmu, DSP_INIT_PAGE);
+               flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
+               free_page((unsigned long)dspvect_page);
+               dspvect_page = NULL;
+
+               up_read(&mmu->exmap_sem);
+       }
+}
+
+static ssize_t omap2_mmu_show(struct omap_mmu *mmu, char *buf,
+                             struct omap_mmu_tlb_lock *tlb_lock)
+{
+       int i, len;
+
+       len = sprintf(buf, "P: preserved, V: valid\n"
+                          "B: big endian, L:little endian, "
+                          "M: mixed page attribute\n"
+                          "ety P V size   cam_va     ram_pa E ES M\n");
+                        /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+
+       for (i = 0; i < mmu->nr_tlb_entries; i++) {
+               struct omap_mmu_tlb_entry ent;
+               struct cam_ram_regset cr;
+               struct omap_mmu_tlb_lock entry_lock;
+               char *pgsz_str, *elsz_str;
+
+               /* read a TLB entry */
+               entry_lock.base   = tlb_lock->base;
+               entry_lock.victim = i;
+               omap_mmu_read_tlb(mmu, &entry_lock, &cr);
+
+               ent.pgsz   = cr.cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+               ent.prsvd  = cr.cam & OMAP_MMU_CAM_P;
+               ent.valid  = cr.cam & OMAP_MMU_CAM_V;
+               ent.va     = cr.cam & OMAP_MMU_CAM_VATAG_MASK;
+               ent.endian = cr.ram & OMAP_MMU_RAM_ENDIANNESS;
+               ent.elsz   = cr.ram & OMAP_MMU_RAM_ELEMENTSIZE_MASK;
+               ent.pa     = cr.ram & OMAP_MMU_RAM_PADDR_MASK;
+               ent.mixed  = cr.ram & OMAP_MMU_RAM_MIXED;
+
+               pgsz_str = (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_16MB) ? "64MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_1MB)  ? " 1MB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_64KB) ? "64KB":
+                          (ent.pgsz == OMAP_MMU_CAM_PAGESIZE_4KB)  ? " 4KB":
+                                                                    " ???";
+               elsz_str = (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_8)  ? " 8":
+                          (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_16) ? "16":
+                          (ent.elsz == OMAP_MMU_RAM_ELEMENTSIZE_32) ? "32":
+                                                                     "??";
+
+               if (i == tlb_lock->base)
+                       len += sprintf(buf + len, "lock base = %d\n",
+                                      tlb_lock->base);
+               if (i == tlb_lock->victim)
+                       len += sprintf(buf + len, "victim    = %d\n",
+                                      tlb_lock->victim);
+
+               len += sprintf(buf + len,
+                              /* 00: P V  4KB 0x300000 0x10171800 B 16 M */
+                              "%02d: %c %c %s 0x%06lx 0x%08lx %c %s %c\n",
+                              i,
+                              ent.prsvd ? 'P' : ' ',
+                              ent.valid ? 'V' : ' ',
+                              pgsz_str, ent.va, ent.pa,
+                              ent.endian ? 'B' : 'L',
+                              elsz_str,
+                              ent.mixed ? 'M' : ' ');
+       }
+
+       return len;
+}
+
+#define get_cam_va_mask(pgsz) \
+       (((pgsz) == OMAP_MMU_CAM_PAGESIZE_16MB) ? 0xff000000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_1MB)  ? 0xfff00000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_64KB) ? 0xffff0000 : \
+        ((pgsz) == OMAP_MMU_CAM_PAGESIZE_4KB)  ? 0xfffff000 : 0)
+
+static inline unsigned long omap2_mmu_cam_va(struct cam_ram_regset *cr)
+{
+       unsigned int page_size = cr->cam & OMAP_MMU_CAM_PAGESIZE_MASK;
+       unsigned int mask = get_cam_va_mask(cr->cam & page_size);
+
+       return cr->cam & mask;
+}
+
+static struct cam_ram_regset *
+omap2_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+       struct cam_ram_regset *cr;
+
+       if (entry->va & ~(get_cam_va_mask(entry->pgsz))) {
+               dev_err(mmu->dev, "MMU %s: mapping vadr (0x%06lx) is not on"
+                       " an aligned boundary\n", mmu->name, entry->va);
+               return ERR_PTR(-EINVAL);
+       }
+
+       cr = kmalloc(sizeof(struct cam_ram_regset), GFP_KERNEL);
+
+       cr->cam = (entry->va & OMAP_MMU_CAM_VATAG_MASK) |
+                 entry->prsvd | entry->pgsz;
+       cr->ram = entry->pa | entry->endian | entry->elsz;
+
+       return cr;
+}
+
+static inline int omap2_mmu_cam_ram_valid(struct cam_ram_regset *cr)
+{
+       return cr->cam & OMAP_MMU_CAM_V;
+}
+
+static void omap2_mmu_interrupt(struct omap_mmu *mmu)
+{
+       unsigned long status, va;
+
+       status = MMU_IRQ_MASK & omap_mmu_read_reg(mmu, OMAP_MMU_IRQSTATUS);
+       va = omap_mmu_read_reg(mmu, OMAP_MMU_FAULT_AD);
+
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_MULTIHITFAULT)?
+               "multi hit":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TABLEWALKFAULT)?
+               "table walk fault":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_EMUMISS)?
+               "EMU miss":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TRANSLATIONFAULT)?
+               "translation fault":"");
+       pr_info("%s\n", (status & OMAP_MMU_IRQ_TLBMISS)?
+               "TLB miss":"");
+       pr_info("fault address = %#08lx\n", va);
+
+       omap_mmu_disable(mmu);
+       omap_mmu_write_reg(mmu, status, OMAP_MMU_IRQSTATUS);
+
+       mmu->fault_address = va;
+       schedule_work(&mmu->irq_work);
+}
+
+static pgprot_t omap2_mmu_pte_get_attr(struct omap_mmu_tlb_entry *entry)
+{
+       u32 attr;
+
+       attr = entry->mixed << 5;
+       attr |= entry->endian;
+       attr |= entry->elsz >> 3;
+       attr <<= ((entry->pgsz & OMAP_MMU_CAM_PAGESIZE_4KB) ? 0:6);
+
+       return attr;
+}
+
+struct omap_mmu_ops omap2_mmu_ops = {
+       .startup        = omap2_mmu_startup,
+       .shutdown       = omap2_mmu_shutdown,
+       .read_tlb       = omap2_mmu_read_tlb,
+       .load_tlb       = omap2_mmu_load_tlb,
+       .show           = omap2_mmu_show,
+       .cam_va         = omap2_mmu_cam_va,
+       .cam_ram_alloc  = omap2_mmu_cam_ram_alloc,
+       .cam_ram_valid  = omap2_mmu_cam_ram_valid,
+       .interrupt      = omap2_mmu_interrupt,
+       .pte_get_attr   = omap2_mmu_pte_get_attr,
+};
+EXPORT_SYMBOL_GPL(omap2_mmu_ops);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap2/mmu.h b/arch/arm/mach-omap2/mmu.h
new file mode 100644 (file)
index 0000000..c9eabf0
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef __MACH_OMAP2_MMU_H
+#define __MACH_OMAP2_MMU_H
+
+#include <linux/io.h>
+#include <mach/mmu.h>
+
+#define MMU_LOCK_BASE_MASK             (0x1f << 10)
+#define MMU_LOCK_VICTIM_MASK           (0x1f << 4)
+
+#define OMAP_MMU_REVISION              0x00
+#define OMAP_MMU_SYSCONFIG             0x10
+#define OMAP_MMU_SYSSTATUS             0x14
+#define OMAP_MMU_IRQSTATUS             0x18
+#define OMAP_MMU_IRQENABLE             0x1c
+#define OMAP_MMU_WALKING_ST            0x40
+#define OMAP_MMU_CNTL                  0x44
+#define OMAP_MMU_FAULT_AD              0x48
+#define OMAP_MMU_TTB                   0x4c
+#define OMAP_MMU_LOCK                  0x50
+#define OMAP_MMU_LD_TLB                        0x54
+#define OMAP_MMU_CAM                   0x58
+#define OMAP_MMU_RAM                   0x5c
+#define OMAP_MMU_GFLUSH                        0x60
+#define OMAP_MMU_FLUSH_ENTRY           0x64
+#define OMAP_MMU_READ_CAM              0x68
+#define OMAP_MMU_READ_RAM              0x6c
+#define OMAP_MMU_EMU_FAULT_AD          0x70
+
+#define OMAP_MMU_CNTL_BURST_16MNGT_EN   0x0020
+#define OMAP_MMU_CNTL_WTL_EN            0x0004
+#define OMAP_MMU_CNTL_MMU_EN            0x0002
+#define OMAP_MMU_CNTL_RESET_SW          0x0001
+
+#define OMAP_MMU_IRQ_MULTIHITFAULT     0x00000010
+#define OMAP_MMU_IRQ_TABLEWALKFAULT    0x00000008
+#define OMAP_MMU_IRQ_EMUMISS           0x00000004
+#define OMAP_MMU_IRQ_TRANSLATIONFAULT  0x00000002
+#define OMAP_MMU_IRQ_TLBMISS           0x00000001
+
+#define OMAP_MMU_CAM_VATAG_MASK                0xfffff000
+#define OMAP_MMU_CAM_P                 0x00000008
+#define OMAP_MMU_CAM_V                 0x00000004
+#define OMAP_MMU_CAM_PAGESIZE_MASK     0x00000003
+#define OMAP_MMU_CAM_PAGESIZE_1MB      0x00000000
+#define OMAP_MMU_CAM_PAGESIZE_64KB     0x00000001
+#define OMAP_MMU_CAM_PAGESIZE_4KB      0x00000002
+#define OMAP_MMU_CAM_PAGESIZE_16MB     0x00000003
+
+#define OMAP_MMU_RAM_PADDR_MASK                0xfffff000
+#define OMAP_MMU_RAM_ENDIANNESS                0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_BIG    0x00000200
+#define OMAP_MMU_RAM_ENDIANNESS_LITTLE 0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_MASK  0x00000180
+#define OMAP_MMU_RAM_ELEMENTSIZE_8     0x00000000
+#define OMAP_MMU_RAM_ELEMENTSIZE_16    0x00000080
+#define OMAP_MMU_RAM_ELEMENTSIZE_32    0x00000100
+#define OMAP_MMU_RAM_ELEMENTSIZE_NONE  0x00000180
+#define OMAP_MMU_RAM_MIXED             0x00000040
+
+#define IOMAP_VAL      0x3f
+
+#define INIT_TLB_ENTRY(ent, v, p, ps)                          \
+do {                                                           \
+       (ent)->va       = (v);                                  \
+       (ent)->pa       = (p);                                  \
+       (ent)->pgsz     = (ps);                                 \
+       (ent)->prsvd    = 0;                                    \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_MMU_RAM_ELEMENTSIZE_16;          \
+       (ent)->mixed    = 0;                                    \
+       (ent)->tlb      = 1;                                    \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_PRESERVED(ent, v, p)                \
+do {                                                           \
+       (ent)->va       = (v);                                  \
+       (ent)->pa       = (p);                                  \
+       (ent)->pgsz     = OMAP_MMU_CAM_PAGESIZE_4KB;            \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;                       \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_MMU_RAM_ELEMENTSIZE_16;          \
+       (ent)->mixed    = 0;                                    \
+} while (0)
+
+#define INIT_TLB_ENTRY_4KB_ES32_PRESERVED(ent, v, p)           \
+do {                                                           \
+       (ent)->va       = (v);                                  \
+       (ent)->pa       = (p);                                  \
+       (ent)->pgsz     = OMAP_MMU_CAM_PAGESIZE_4KB;            \
+       (ent)->prsvd    = OMAP_MMU_CAM_P;                       \
+       (ent)->endian   = OMAP_MMU_RAM_ENDIANNESS_LITTLE;       \
+       (ent)->elsz     = OMAP_MMU_RAM_ELEMENTSIZE_32;          \
+       (ent)->mixed    = 0;                                    \
+} while (0)
+
+struct omap_mmu_tlb_entry {
+       unsigned long va;
+       unsigned long pa;
+       unsigned int pgsz, prsvd, valid;
+
+       u32 endian, elsz, mixed;
+       unsigned int tlb;
+};
+
+static inline unsigned long
+omap_mmu_read_reg(struct omap_mmu *mmu, unsigned long reg)
+{
+       return __raw_readl((void __iomem *)(mmu->base + reg));
+}
+
+static inline void omap_mmu_write_reg(struct omap_mmu *mmu,
+                              unsigned long val, unsigned long reg)
+{
+       __raw_writel(val, (void __iomem *)(mmu->base + reg));
+}
+
+#endif /* __MACH_OMAP2_MMU_H */
index 443d07fef7f3155ee06b9e877d17d7286cd3b43c..ba37764a9e451c728be65b2927a5fda4cb2e0dc3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/arch/arm/mach-omap2/mux.c
  *
- * OMAP2 pin multiplexing configurations
+ * OMAP2 and OMAP3 pin multiplexing configurations
  *
  * Copyright (C) 2004 - 2008 Texas Instruments Inc.
  * Copyright (C) 2003 - 2008 Nokia Corporation
@@ -26,7 +26,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/spinlock.h>
 
 #include <mach/control.h>
@@ -219,16 +219,230 @@ MUX_CFG_24XX("AD13_2430_MCBSP2_DR_OFF",  0x0131, 0,      0,      0,      1)
 #define OMAP24XX_PINS_SZ       0
 #endif /* CONFIG_ARCH_OMAP24XX */
 
-#define OMAP24XX_PULL_ENA      (1 << 3)
-#define OMAP24XX_PULL_UP       (1 << 4)
+#ifdef CONFIG_ARCH_OMAP34XX
+static struct pin_config __initdata_or_module omap34xx_pins[] = {
+/*
+ *             Name, reg-offset,
+ *             mux-mode | [active-mode | off-mode]
+ */
+
+/* 34xx I2C */
+MUX_CFG_34XX("K21_34XX_I2C1_SCL", 0x1ba,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("J21_34XX_I2C1_SDA", 0x1bc,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF15_34XX_I2C2_SCL", 0x1be,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE15_34XX_I2C2_SDA", 0x1c0,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF14_34XX_I2C3_SCL", 0x1c2,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AG14_34XX_I2C3_SDA", 0x1c4,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AD26_34XX_I2C4_SCL", 0xa00,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE26_34XX_I2C4_SDA", 0xa02,
+               OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_PHY_CLK", 0x5da,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("Y9_3430_USB1HS_PHY_STP", 0x5d8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA14_3430_USB1HS_PHY_DIR", 0x5ec,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA11_3430_USB1HS_PHY_NXT", 0x5ee,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1HS_PHY_D0", 0x5dc,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_PHY_D1", 0x5de,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_PHY_D2", 0x5e0,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_PHY_D3", 0x5ea,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_PHY_D4", 0x5e4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_PHY_D5", 0x5e6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_PHY_D6", 0x5e8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_PHY_D7", 0x5e2,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_PHY_CLK", 0x5f0,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA10_3430_USB2HS_PHY_STP", 0x5f2,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("AA9_3430_USB2HS_PHY_DIR", 0x5f4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB11_3430_USB2HS_PHY_NXT", 0x5f6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2HS_PHY_D0", 0x5f8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_PHY_D1", 0x5fa,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_PHY_D2", 0x1d4,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_PHY_D3", 0x1de,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_PHY_D4", 0x1d8,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_PHY_D5", 0x1da,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_PHY_D6", 0x1dc,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_PHY_D7", 0x1d6,
+               OMAP34XX_MUX_MODE3 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 1*/
+MUX_CFG_34XX("Y8_3430_USB1HS_TLL_CLK", 0x5da,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y9_3430_USB1HS_TLL_STP", 0x5d8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA14_3430_USB1HS_TLL_DIR", 0x5ec,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA11_3430_USB1HS_TLL_NXT", 0x5ee,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1HS_TLL_D0", 0x5dc,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1HS_TLL_D1", 0x5de,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1HS_TLL_D2", 0x5e0,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1HS_TLL_D3", 0x5ea,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W9_3430_USB1HS_TLL_D4", 0x5e4,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y12_3430_USB1HS_TLL_D5", 0x5e6,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W8_3430_USB1HS_TLL_D6", 0x5e8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y13_3430_USB1HS_TLL_D7", 0x5e2,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 2*/
+MUX_CFG_34XX("AA8_3430_USB2HS_TLL_CLK", 0x5f0,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA10_3430_USB2HS_TLL_STP", 0x5f2,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA9_3430_USB2HS_TLL_DIR", 0x5f4,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB11_3430_USB2HS_TLL_NXT", 0x5f6,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2HS_TLL_D0", 0x5f8,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2HS_TLL_D1", 0x5fa,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2HS_TLL_D2", 0x1d4,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2HS_TLL_D3", 0x1de,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T3_3430_USB2HS_TLL_D4", 0x1d8,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R3_3430_USB2HS_TLL_D5", 0x1da,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("R4_3430_USB2HS_TLL_D6", 0x1dc,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T2_3430_USB2HS_TLL_D7", 0x1d6,
+               OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* TLL - HSUSB: 12-pin TLL Port 3*/
+MUX_CFG_34XX("AA6_3430_USB3HS_TLL_CLK", 0x180,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB3_3430_USB3HS_TLL_STP", 0x166,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AA3_3430_USB3HS_TLL_DIR", 0x168,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y3_3430_USB3HS_TLL_NXT", 0x16a,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA5_3430_USB3HS_TLL_D0", 0x186,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y4_3430_USB3HS_TLL_D1", 0x184,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y5_3430_USB3HS_TLL_D2", 0x188,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W5_3430_USB3HS_TLL_D3", 0x18a,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB12_3430_USB3HS_TLL_D4", 0x16c,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB13_3430_USB3HS_TLL_D5", 0x16e,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA13_3430_USB3HS_TLL_D6", 0x170,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AA12_3430_USB3HS_TLL_D7", 0x172,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+
+/* PHY FSUSB: FS Serial for Port 1 (multiple PHY modes supported) */
+MUX_CFG_34XX("AF10_3430_USB1FS_PHY_MM1_RXDP", 0x5d8,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AG9_3430_USB1FS_PHY_MM1_RXDM", 0x5ee,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W13_3430_USB1FS_PHY_MM1_RXRCV", 0x5dc,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W12_3430_USB1FS_PHY_MM1_TXSE0", 0x5de,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W11_3430_USB1FS_PHY_MM1_TXDAT", 0x5e0,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("Y11_3430_USB1FS_PHY_MM1_TXEN_N", 0x5ea,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+
+/* PHY FSUSB: FS Serial for Port 2 (multiple PHY modes supported) */
+MUX_CFG_34XX("AF7_3430_USB2FS_PHY_MM2_RXDP", 0x5f2,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AH7_3430_USB2FS_PHY_MM2_RXDM", 0x5f6,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB10_3430_USB2FS_PHY_MM2_RXRCV", 0x5f8,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AB9_3430_USB2FS_PHY_MM2_TXSE0", 0x5fa,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("W3_3430_USB2FS_PHY_MM2_TXDAT", 0x1d4,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("T4_3430_USB2FS_PHY_MM2_TXEN_N", 0x1de,
+               OMAP34XX_MUX_MODE5 | OMAP34XX_PIN_OUTPUT)
+
+/* PHY FSUSB: FS Serial for Port 3 (multiple PHY modes supported) */
+MUX_CFG_34XX("AH3_3430_USB3FS_PHY_MM3_RXDP", 0x166,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AE3_3430_USB3FS_PHY_MM3_RXDM", 0x16a,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AD1_3430_USB3FS_PHY_MM3_RXRCV", 0x186,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AE1_3430_USB3FS_PHY_MM3_TXSE0", 0x184,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AD2_3430_USB3FS_PHY_MM3_TXDAT", 0x188,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("AC1_3430_USB3FS_PHY_MM3_TXEN_N", 0x18a,
+               OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT)
+
+
+/* 34XX GPIO - bidirectional, unless the name has an "_OUT" suffix.
+ * No internal pullup/pulldown without "_UP" or "_DOWN" suffix.
+ */
+MUX_CFG_34XX("AH8_34XX_GPIO29", 0x5fa,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6,
+               OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
+};
+
+#define OMAP34XX_PINS_SZ       ARRAY_SIZE(omap34xx_pins)
+
+#else
+#define omap34xx_pins          NULL
+#define OMAP34XX_PINS_SZ       0
+#endif /* CONFIG_ARCH_OMAP34XX */
 
 #if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
-void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u8 reg)
+static void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 reg)
 {
        u16 orig;
        u8 warn = 0, debug = 0;
 
-       orig = omap_ctrl_readb(cfg->mux_reg);
+       if (cpu_is_omap24xx())
+               orig = omap_ctrl_readb(cfg->mux_reg);
+       else
+               orig = omap_ctrl_readw(cfg->mux_reg);
 
 #ifdef CONFIG_OMAP_MUX_DEBUG
        debug = cfg->debug;
@@ -245,7 +459,7 @@ void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u8 reg)
 #endif
 
 #ifdef CONFIG_ARCH_OMAP24XX
-int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
+static int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
 {
        static DEFINE_SPINLOCK(mux_spin_lock);
        unsigned long flags;
@@ -254,9 +468,9 @@ int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
        spin_lock_irqsave(&mux_spin_lock, flags);
        reg |= cfg->mask & 0x7;
        if (cfg->pull_val)
-               reg |= OMAP24XX_PULL_ENA;
+               reg |= OMAP2_PULL_ENA;
        if (cfg->pu_pd_val)
-               reg |= OMAP24XX_PULL_UP;
+               reg |= OMAP2_PULL_UP;
        omap2_cfg_debug(cfg, reg);
        omap_ctrl_writeb(reg, cfg->mux_reg);
        spin_unlock_irqrestore(&mux_spin_lock, flags);
@@ -264,7 +478,26 @@ int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg)
        return 0;
 }
 #else
-#define omap24xx_cfg_reg       0
+#define omap24xx_cfg_reg       NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static int __init_or_module omap34xx_cfg_reg(const struct pin_config *cfg)
+{
+       static DEFINE_SPINLOCK(mux_spin_lock);
+       unsigned long flags;
+       u16 reg = 0;
+
+       spin_lock_irqsave(&mux_spin_lock, flags);
+       reg |= cfg->mux_val;
+       omap2_cfg_debug(cfg, reg);
+       omap_ctrl_writew(reg, cfg->mux_reg);
+       spin_unlock_irqrestore(&mux_spin_lock, flags);
+
+       return 0;
+}
+#else
+#define omap34xx_cfg_reg       NULL
 #endif
 
 int __init omap2_mux_init(void)
@@ -273,6 +506,10 @@ int __init omap2_mux_init(void)
                arch_mux_cfg.pins       = omap24xx_pins;
                arch_mux_cfg.size       = OMAP24XX_PINS_SZ;
                arch_mux_cfg.cfg_reg    = omap24xx_cfg_reg;
+       } else if (cpu_is_omap34xx()) {
+               arch_mux_cfg.pins       = omap34xx_pins;
+               arch_mux_cfg.size       = OMAP34XX_PINS_SZ;
+               arch_mux_cfg.cfg_reg    = omap34xx_cfg_reg;
        }
 
        return omap_mux_register(&arch_mux_cfg);
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644 (file)
index 0000000..0b5c044
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * linux/arch/arm/mach-omap2/pm_debug.c
+ *
+ * OMAP Power Management debug routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
+ *
+ * Based on pm.c for omap2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/clock.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "cm.h"
+#include "pm.h"
+
+#ifdef CONFIG_PM_DEBUG
+int omap2_pm_debug = 0;
+
+static int serial_console_clock_disabled;
+static int serial_console_uart;
+static unsigned int serial_console_next_disable;
+
+static struct clk *console_iclk, *console_fclk;
+
+static void serial_console_kick(void)
+{
+       serial_console_next_disable = omap2_read_32k_sync_counter();
+       /* Keep the clocks on for 4 secs */
+       serial_console_next_disable += 4 * 32768;
+}
+
+static void serial_wait_tx(void)
+{
+       static const unsigned long uart_bases[3] = {
+               0x4806a000, 0x4806c000, 0x4806e000
+       };
+       unsigned long lsr_reg;
+       int looped = 0;
+
+       /* Wait for TX FIFO and THR to get empty */
+       lsr_reg = IO_ADDRESS(uart_bases[serial_console_uart - 1] + (5 << 2));
+       while ((__raw_readb(lsr_reg) & 0x60) != 0x60)
+               looped = 1;
+       if (looped)
+               serial_console_kick();
+}
+
+u32 omap2_read_32k_sync_counter(void)
+{
+        return omap_readl(OMAP2_32KSYNCT_BASE + 0x0010);
+}
+
+void serial_console_fclk_mask(u32 *f1, u32 *f2)
+{
+       switch (serial_console_uart)  {
+       case 1:
+               *f1 &= ~(1 << 21);
+               break;
+       case 2:
+               *f1 &= ~(1 << 22);
+               break;
+       case 3:
+               *f2 &= ~(1 << 2);
+               break;
+       }
+}
+
+void serial_console_sleep(int enable)
+{
+       if (console_iclk == NULL || console_fclk == NULL)
+               return;
+
+       if (enable) {
+               BUG_ON(serial_console_clock_disabled);
+               if (clk_get_usecount(console_fclk) == 0)
+                       return;
+               if ((int) serial_console_next_disable - (int) omap2_read_32k_sync_counter() >= 0)
+                       return;
+               serial_wait_tx();
+               clk_disable(console_iclk);
+               clk_disable(console_fclk);
+               serial_console_clock_disabled = 1;
+       } else {
+               int serial_wakeup = 0;
+               u32 l;
+
+               switch (serial_console_uart)  {
+               case 1:
+                       l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+                       if (l & OMAP24XX_ST_UART1_MASK)
+                               serial_wakeup = 1;
+                       break;
+               case 2:
+                       l = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+                       if (l & OMAP24XX_ST_UART2_MASK)
+                               serial_wakeup = 1;
+                       break;
+               case 3:
+                       l = prm_read_mod_reg(CORE_MOD, OMAP24XX_PM_WKST2);
+                       if (l & OMAP24XX_ST_UART3_MASK)
+                               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;
+       }
+}
+
+void pm_init_serial_console(void)
+{
+       const struct omap_serial_console_config *conf;
+       char name[16];
+
+       conf = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+                              struct omap_serial_console_config);
+       if (conf == NULL)
+               return;
+       if (conf->console_uart > 3 || conf->console_uart < 1)
+               return;
+       serial_console_uart = conf->console_uart;
+       sprintf(name, "uart%d_fck", conf->console_uart);
+       console_fclk = clk_get(NULL, name);
+       if (IS_ERR(console_fclk))
+               console_fclk = NULL;
+       name[6] = 'i';
+       console_iclk = clk_get(NULL, name);
+       if (IS_ERR(console_fclk))
+               console_iclk = NULL;
+       if (console_fclk == NULL || console_iclk == NULL) {
+               serial_console_uart = 0;
+               return;
+       }
+       switch (serial_console_uart) {
+       case 1:
+               prm_set_mod_reg_bits(OMAP24XX_ST_UART1_MASK, CORE_MOD,
+                                    PM_WKEN1);
+               break;
+       case 2:
+               prm_set_mod_reg_bits(OMAP24XX_ST_UART2_MASK, CORE_MOD,
+                                    PM_WKEN1);
+               break;
+       case 3:
+               prm_set_mod_reg_bits(OMAP24XX_ST_UART3_MASK, CORE_MOD,
+                                    OMAP24XX_PM_WKEN2);
+               break;
+       }
+}
+
+#define DUMP_PRM_MOD_REG(mod, reg)    \
+       regs[reg_count].name = #mod "." #reg; \
+       regs[reg_count++].val = prm_read_mod_reg(mod, reg)
+#define DUMP_CM_MOD_REG(mod, reg)     \
+       regs[reg_count].name = #mod "." #reg; \
+       regs[reg_count++].val = cm_read_mod_reg(mod, reg)
+#define DUMP_PRM_REG(reg) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_CM_REG(reg) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(reg)
+#define DUMP_INTC_REG(reg, off) \
+       regs[reg_count].name = #reg; \
+       regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
+
+void omap2_pm_dump(int mode, int resume, unsigned int us)
+{
+       struct reg {
+               const char *name;
+               u32 val;
+       } regs[32];
+       int reg_count = 0, i;
+       const char *s1 = NULL, *s2 = NULL;
+
+       if (!resume) {
+#if 0
+               /* MPU */
+               DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+               DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
+               DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
+#endif
+#if 0
+               /* INTC */
+               DUMP_INTC_REG(INTC_MIR0, 0x0084);
+               DUMP_INTC_REG(INTC_MIR1, 0x00a4);
+               DUMP_INTC_REG(INTC_MIR2, 0x00c4);
+#endif
+#if 0
+               DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
+               if (cpu_is_omap24xx()) {
+                       DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+                       DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+                                       OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET);
+                       DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
+                                       OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET);
+               }
+               DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
+               DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
+               DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
+               DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
+               DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
+               DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
+               DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
+#endif
+#if 0
+               /* DSP */
+               if (cpu_is_omap24xx()) {
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
+                       DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
+                       DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
+               }
+#endif
+       } else {
+               DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
+               if (cpu_is_omap24xx())
+                       DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
+               DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
+               DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+#if 1
+               DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
+               DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
+               DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
+#endif
+       }
+
+       switch (mode) {
+       case 0:
+               s1 = "full";
+               s2 = "retention";
+               break;
+       case 1:
+               s1 = "MPU";
+               s2 = "retention";
+               break;
+       case 2:
+               s1 = "MPU";
+               s2 = "idle";
+               break;
+       }
+
+       if (!resume)
+#if defined(CONFIG_NO_IDLE_HZ) || defined(CONFIG_NO_HZ)
+               printk("--- Going to %s %s (next timer after %u ms)\n", s1, s2,
+                      jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
+                                       jiffies));
+#else
+               printk("--- Going to %s %s\n", s1, s2);
+#endif
+       else
+               printk("--- Woke up (slept for %u.%03u ms)\n",
+                       us / 1000, us % 1000);
+
+       for (i = 0; i < reg_count; i++)
+               printk("%-20s: 0x%08x\n", regs[i].name, regs[i].val);
+}
+
+#endif
index 8671e1079ab54c7764adfe729294e793e9504d17..4652136de15f7150b61496d0bd190bb0e785cd1b 100644 (file)
@@ -1,13 +1,18 @@
 /*
  * linux/arch/arm/mach-omap2/pm.c
  *
- * OMAP2 Power Management Routines
- *
- * Copyright (C) 2006 Nokia Corporation
- * Tony Lindgren <tony@atomide.com>
+ * OMAP Power Management Common Routines
  *
  * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
  * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ * Jouni Hogander
  *
  * Based on pm.c for omap1
  *
  */
 
 #include <linux/suspend.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/interrupt.h>
-#include <linux/sysfs.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/atomic.h>
+#include <linux/time.h>
+
+#include <mach/cpu.h>
 #include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+#include <asm/atomic.h>
 
-#include <mach/irqs.h>
-#include <mach/clock.h>
-#include <mach/sram.h>
 #include <mach/pm.h>
+#include "pm.h"
 
-static struct clk *vclk;
-static void (*omap2_sram_idle)(void);
-static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
-static void (*saved_idle)(void);
+unsigned short enable_dyn_sleep;
+unsigned short clocks_off_while_idle;
+atomic_t sleep_block = ATOMIC_INIT(0);
 
-extern void __init pmdomain_init(void);
-extern void pmdomain_set_autoidle(void);
+static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
+static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
+                         const char *buf, size_t n);
 
-static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
+static struct kobj_attribute sleep_while_idle_attr =
+       __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
 
-void omap2_pm_idle(void)
-{
-       local_irq_disable();
-       local_fiq_disable();
-       if (need_resched()) {
-               local_fiq_enable();
-               local_irq_enable();
-               return;
-       }
-
-       omap2_sram_idle();
-       local_fiq_enable();
-       local_irq_enable();
-}
+static struct kobj_attribute clocks_off_while_idle_attr =
+       __ATTR(clocks_off_while_idle, 0644, idle_show, idle_store);
 
-static int omap2_pm_prepare(void)
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+                        char *buf)
 {
-       /* We cannot sleep in idle until we have resumed */
-       saved_idle = pm_idle;
-       pm_idle = NULL;
-       return 0;
+       if (attr == &sleep_while_idle_attr)
+               return sprintf(buf, "%hu\n", enable_dyn_sleep);
+       else if (attr == &clocks_off_while_idle_attr)
+               return sprintf(buf, "%hu\n", clocks_off_while_idle);
+       else
+               return -EINVAL;
 }
 
-static int omap2_pm_suspend(void)
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+                         const char *buf, size_t n)
 {
-       return 0;
-}
+       unsigned short value;
 
-static int omap2_pm_enter(suspend_state_t state)
-{
-       int ret = 0;
-
-       switch (state)
-       {
-       case PM_SUSPEND_STANDBY:
-       case PM_SUSPEND_MEM:
-               ret = omap2_pm_suspend();
-               break;
-       default:
-               ret = -EINVAL;
+       if (sscanf(buf, "%hu", &value) != 1 ||
+           (value != 0 && value != 1)) {
+               printk(KERN_ERR "idle_store: Invalid value\n");
+               return -EINVAL;
        }
 
-       return ret;
+       if (attr == &sleep_while_idle_attr)
+               enable_dyn_sleep = value;
+       else if (attr == &clocks_off_while_idle_attr)
+               clocks_off_while_idle = value;
+       else
+               return -EINVAL;
+
+       return n;
 }
 
-static void omap2_pm_finish(void)
+void omap2_block_sleep(void)
 {
-       pm_idle = saved_idle;
+       atomic_inc(&sleep_block);
 }
 
-static struct platform_suspend_ops omap_pm_ops = {
-       .prepare        = omap2_pm_prepare,
-       .enter          = omap2_pm_enter,
-       .finish         = omap2_pm_finish,
-       .valid          = suspend_valid_only_mem,
-};
+void omap2_allow_sleep(void)
+{
+       int i;
+
+       i = atomic_dec_return(&sleep_block);
+       BUG_ON(i < 0);
+}
 
-int __init omap2_pm_init(void)
+static int __init omap_pm_init(void)
 {
-       return 0;
+       int error = -1;
+
+       if (cpu_is_omap24xx())
+               error = omap2_pm_init();
+       if (cpu_is_omap34xx())
+               error = omap3_pm_init();
+       if (error) {
+               printk(KERN_ERR "omap2|3_pm_init failed: %d\n", error);
+               return error;
+       }
+
+       /* disabled till drivers are fixed */
+       enable_dyn_sleep = 0;
+       error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+       if (error)
+               printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+       error = sysfs_create_file(power_kobj,
+                                 &clocks_off_while_idle_attr.attr);
+       if (error)
+               printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+       return error;
 }
 
-__initcall(omap2_pm_init);
+late_initcall(omap_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644 (file)
index 0000000..68c9278
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
+#define __ARCH_ARM_MACH_OMAP2_PM_H
+/*
+ * linux/arch/arm/mach-omap2/pm.h
+ *
+ * OMAP Power Management Routines
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Jouni Hogander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+extern int omap2_pm_init(void);
+extern int omap3_pm_init(void);
+
+extern unsigned short enable_dyn_sleep;
+extern unsigned short clocks_off_while_idle;
+extern atomic_t sleep_block;
+
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+
+
+#ifdef CONFIG_PM_DEBUG
+extern u32 omap2_read_32k_sync_counter(void);
+extern void omap2_pm_dump(int mode, int resume, unsigned int us);
+extern void serial_console_fclk_mask(u32 *f1, u32 *f2);
+extern void pm_init_serial_console(void);
+extern void serial_console_sleep(int enable);
+extern int omap2_pm_debug;
+#else
+#define omap2_read_32k_sync_counter()          0
+#define serial_console_sleep(enable)           do {} while (0);
+#define pm_init_serial_console()               do {} while (0);
+#define omap2_pm_dump(mode, resume, us)                do {} while (0);
+#define serial_console_fclk_mask(f1, f2)               do {} while (0);
+#define omap2_pm_debug                         0
+#endif /* CONFIG_PM_DEBUG */
+#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644 (file)
index 0000000..60ff04f
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * linux/arch/arm/mach-omap2/pm.c
+ *
+ * OMAP2 Power Management Routines
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Written by:
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Tony Lindgren
+ * Juha Yrjola
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Igor Stoppa <igor.stoppa@nokia.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+#include <mach/control.h>
+#include <mach/gpio.h>
+#include <mach/pm.h>
+#include <mach/mux.h>
+#include <mach/dma.h>
+#include <mach/board.h>
+
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+#include "sdrc.h"
+#include "pm.h"
+
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+static void (*omap2_sram_idle)(void);
+static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
+                                       void __iomem *sdrc_power);
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *core_pwrdm;
+
+static struct clockdomain *dsp_clkdm;
+static struct clockdomain *gfx_clkdm;
+
+static struct clk *osc_ck, *emul_ck;
+
+static int omap2_fclks_active(void)
+{
+       u32 f1, f2;
+
+       f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+       serial_console_fclk_mask(&f1, &f2);
+       if (f1 | f2)
+               return 1;
+       return 0;
+}
+
+static void omap2_enter_full_retention(void)
+{
+       u32 l, sleep_time = 0;
+
+       /* There is 1 reference hold for all children of the oscillator
+        * clock, the following will remove it. If no one else uses the
+        * oscillator itself it will be disabled if/when we enter retention
+        * mode.
+        */
+       clk_disable(osc_ck);
+
+       /* Clear old wake-up events */
+       /* REVISIT: These write to reserved bits? */
+       prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+       prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+       /*
+        * Set MPU powerdomain's next power state to RETENTION;
+        * preserve logic state during retention
+        */
+       pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+       pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+       /* Workaround to kill USB */
+       l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
+       omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
+
+       omap2_gpio_prepare_for_retention();
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(0, 0, 0);
+               sleep_time = omap2_read_32k_sync_counter();
+       }
+
+       /* One last check for pending IRQs to avoid extra latency due
+        * to sleeping unnecessarily. */
+       if (omap_irq_pending())
+               goto no_sleep;
+
+       serial_console_sleep(1);
+       /* Jump to SRAM suspend code */
+       omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
+                               OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
+                               OMAP_SDRC_REGADDR(SDRC_POWER));
+no_sleep:
+       serial_console_sleep(0);
+
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+               u32 resume_time;
+
+               resume_time = omap2_read_32k_sync_counter();
+               tmp = resume_time - sleep_time;
+               tmp *= 1000000;
+               omap2_pm_dump(0, 1, tmp / 32768);
+       }
+       omap2_gpio_resume_after_retention();
+
+       clk_enable(osc_ck);
+
+       /* clear CORE wake-up events */
+       prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+       prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+
+       /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
+       prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
+
+       /* MPU domain wake events */
+       l = prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+       if (l & 0x01)
+               prm_write_mod_reg(0x01, OCP_MOD,
+                               OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+       if (l & 0x20)
+               prm_write_mod_reg(0x20, OCP_MOD,
+                               OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+       /* Mask future PRCM-to-MPU interrupts */
+       prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+}
+
+static int omap2_i2c_active(void)
+{
+       u32 l;
+
+       l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
+}
+
+static int sti_console_enabled;
+
+static int omap2_allow_mpu_retention(void)
+{
+       u32 l;
+
+       if (atomic_read(&sleep_block))
+               return 0;
+
+       /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
+       l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+       if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
+                OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
+                OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
+               return 0;
+       /* Check for UART3. */
+       l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
+       if (l & OMAP24XX_EN_UART3)
+               return 0;
+       if (sti_console_enabled)
+               return 0;
+
+       return 1;
+}
+
+static void omap2_enter_mpu_retention(void)
+{
+       u32 sleep_time = 0;
+       int only_idle = 0;
+
+       /* Putting MPU into the WFI state while a transfer is active
+        * seems to cause the I2C block to timeout. Why? Good question. */
+       if (omap2_i2c_active())
+               return;
+
+       /* The peripherals seem not to be able to wake up the MPU when
+        * it is in retention mode. */
+       if (omap2_allow_mpu_retention()) {
+               /* REVISIT: These write to reserved bits? */
+               prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
+               prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
+               prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
+
+               /* Try to enter MPU retention */
+               prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
+                                 OMAP_LOGICRETSTATE,
+                                 MPU_MOD, PM_PWSTCTRL);
+       } else {
+               /* Block MPU retention */
+
+               prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
+               only_idle = 1;
+       }
+
+       if (omap2_pm_debug) {
+               omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
+               sleep_time = omap2_read_32k_sync_counter();
+       }
+
+       omap2_sram_idle();
+
+       if (omap2_pm_debug) {
+               unsigned long long tmp;
+               u32 resume_time;
+
+               resume_time = omap2_read_32k_sync_counter();
+               tmp = resume_time - sleep_time;
+               tmp *= 1000000;
+               omap2_pm_dump(only_idle ? 2 : 1, 1, tmp / 32768);
+       }
+}
+
+static int omap2_can_sleep(void)
+{
+       if (!enable_dyn_sleep)
+               return 0;
+       if (omap2_fclks_active())
+               return 0;
+       if (atomic_read(&sleep_block) > 0)
+               return 0;
+       if (clk_get_usecount(osc_ck) > 1)
+               return 0;
+       if (omap_dma_running())
+               return 0;
+
+       return 1;
+}
+
+/*
+ * Note that you can use clock_event_device->min_delta_ns if you want to
+ * avoid reprogramming timer too often when using CONFIG_NO_HZ.
+ */
+static void omap2_pm_idle(void)
+{
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!omap2_can_sleep()) {
+               if (!atomic_read(&sleep_block) && omap_irq_pending())
+                       goto out;
+               omap2_enter_mpu_retention();
+               goto out;
+       }
+
+       if (omap_irq_pending())
+               goto out;
+
+       omap2_enter_full_retention();
+
+out:
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int omap2_pm_prepare(void)
+{
+       /* We cannot sleep in idle until we have resumed */
+       saved_idle = pm_idle;
+       pm_idle = NULL;
+
+       return 0;
+}
+
+static int omap2_pm_suspend(void)
+{
+       u32 wken_wkup, mir1;
+
+       wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
+       prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
+
+       /* Mask GPT1 */
+       mir1 = omap_readl(0x480fe0a4);
+       omap_writel(1 << 5, 0x480fe0ac);
+
+       omap2_enter_full_retention();
+
+       omap_writel(mir1, 0x480fe0a4);
+       prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
+
+       return 0;
+}
+
+static int omap2_pm_enter(suspend_state_t state)
+{
+       int ret = 0;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = omap2_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void omap2_pm_finish(void)
+{
+       pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+       .prepare        = omap2_pm_prepare,
+       .enter          = omap2_pm_enter,
+       .finish         = omap2_pm_finish,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
+{
+       omap2_clkdm_allow_idle(clkdm);
+       return 0;
+}
+
+static void __init prcm_setup_regs(void)
+{
+       int i, num_mem_banks;
+       struct powerdomain *pwrdm;
+
+       /* Enable autoidle */
+       prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
+                               OMAP24XX_PRM_SYSCONFIG_OFFSET);
+
+       /* Set all domain wakeup dependencies */
+       prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
+       if (cpu_is_omap2430())
+               prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
+
+       /*
+        * Set CORE powerdomain memory banks to retain their contents
+        * during RETENTION
+        */
+       num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
+       for (i = 0; i < num_mem_banks; i++)
+               pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
+
+       /* Set CORE powerdomain's next power state to RETENTION */
+       pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
+
+       /*
+        * Set MPU powerdomain's next power state to RETENTION;
+        * preserve logic state during retention
+        */
+       pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
+       pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
+
+       /* Force-power down DSP, GFX powerdomains */
+
+       pwrdm = clkdm_get_pwrdm(dsp_clkdm);
+       pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+       omap2_clkdm_sleep(dsp_clkdm);
+
+       pwrdm = clkdm_get_pwrdm(gfx_clkdm);
+       pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
+       omap2_clkdm_sleep(gfx_clkdm);
+
+       /* Enable clockdomain hardware-supervised control for all clkdms */
+       clkdm_for_each(_pm_clkdm_enable_hwsup);
+
+       /* Enable clock autoidle for all domains */
+       cm_write_mod_reg(OMAP24XX_AUTO_CAM |
+                        OMAP24XX_AUTO_MAILBOXES |
+                        OMAP24XX_AUTO_WDT4 |
+                        OMAP2420_AUTO_WDT3 |
+                        OMAP24XX_AUTO_MSPRO |
+                        OMAP2420_AUTO_MMC |
+                        OMAP24XX_AUTO_FAC |
+                        OMAP2420_AUTO_EAC |
+                        OMAP24XX_AUTO_HDQ |
+                        OMAP24XX_AUTO_UART2 |
+                        OMAP24XX_AUTO_UART1 |
+                        OMAP24XX_AUTO_I2C2 |
+                        OMAP24XX_AUTO_I2C1 |
+                        OMAP24XX_AUTO_MCSPI2 |
+                        OMAP24XX_AUTO_MCSPI1 |
+                        OMAP24XX_AUTO_MCBSP2 |
+                        OMAP24XX_AUTO_MCBSP1 |
+                        OMAP24XX_AUTO_GPT12 |
+                        OMAP24XX_AUTO_GPT11 |
+                        OMAP24XX_AUTO_GPT10 |
+                        OMAP24XX_AUTO_GPT9 |
+                        OMAP24XX_AUTO_GPT8 |
+                        OMAP24XX_AUTO_GPT7 |
+                        OMAP24XX_AUTO_GPT6 |
+                        OMAP24XX_AUTO_GPT5 |
+                        OMAP24XX_AUTO_GPT4 |
+                        OMAP24XX_AUTO_GPT3 |
+                        OMAP24XX_AUTO_GPT2 |
+                        OMAP2420_AUTO_VLYNQ |
+                        OMAP24XX_AUTO_DSS,
+                        CORE_MOD, CM_AUTOIDLE1);
+       cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
+                        OMAP24XX_AUTO_SSI |
+                        OMAP24XX_AUTO_USB,
+                        CORE_MOD, CM_AUTOIDLE2);
+       cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
+                        OMAP24XX_AUTO_GPMC |
+                        OMAP24XX_AUTO_SDMA,
+                        CORE_MOD, CM_AUTOIDLE3);
+       cm_write_mod_reg(OMAP24XX_AUTO_PKA |
+                        OMAP24XX_AUTO_AES |
+                        OMAP24XX_AUTO_RNG |
+                        OMAP24XX_AUTO_SHA |
+                        OMAP24XX_AUTO_DES,
+                        CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
+
+       cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
+
+       /* Put DPLL and both APLLs into autoidle mode */
+       cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
+                        (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
+                        (0x03 << OMAP24XX_AUTO_54M_SHIFT),
+                        PLL_MOD, CM_AUTOIDLE);
+
+       cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
+                        OMAP24XX_AUTO_WDT1 |
+                        OMAP24XX_AUTO_MPU_WDT |
+                        OMAP24XX_AUTO_GPIOS |
+                        OMAP24XX_AUTO_32KSYNC |
+                        OMAP24XX_AUTO_GPT1,
+                        WKUP_MOD, CM_AUTOIDLE);
+
+       /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
+        * stabilisation */
+       prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+                                       OMAP24XX_PRCM_CLKSSETUP_OFFSET);
+
+       /* Configure automatic voltage transition */
+       prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
+                                       OMAP24XX_PRCM_VOLTSETUP_OFFSET);
+       prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
+                     (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
+                     OMAP24XX_MEMRETCTRL |
+                     (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
+                     (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
+                     OMAP24XX_GR_MOD, OMAP24XX_PRCM_VOLTCTRL_OFFSET);
+
+       /* Enable wake-up events */
+       prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
+                         WKUP_MOD, PM_WKEN);
+}
+
+int __init omap2_pm_init(void)
+{
+       u32 l;
+
+       printk(KERN_INFO "Power Management for OMAP2 initializing\n");
+       l = prm_read_mod_reg(OCP_MOD, OMAP24XX_PRM_REVISION_OFFSET);
+       printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
+
+       /* Look up important powerdomains, clockdomains */
+
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+       if (!mpu_pwrdm)
+               pr_err("PM: mpu_pwrdm not found\n");
+
+       core_pwrdm = pwrdm_lookup("core_pwrdm");
+       if (!core_pwrdm)
+               pr_err("PM: core_pwrdm not found\n");
+
+       dsp_clkdm = clkdm_lookup("dsp_clkdm");
+       if (!dsp_clkdm)
+               pr_err("PM: mpu_clkdm not found\n");
+
+       gfx_clkdm = clkdm_lookup("gfx_clkdm");
+       if (!gfx_clkdm)
+               pr_err("PM: gfx_clkdm not found\n");
+
+
+       osc_ck = clk_get(NULL, "osc_ck");
+       if (IS_ERR(osc_ck)) {
+               printk(KERN_ERR "could not get osc_ck\n");
+               return -ENODEV;
+       }
+
+       if (cpu_is_omap242x()) {
+               emul_ck = clk_get(NULL, "emul_ck");
+               if (IS_ERR(emul_ck)) {
+                       printk(KERN_ERR "could not get emul_ck\n");
+                       clk_put(osc_ck);
+                       return -ENODEV;
+               }
+       }
+
+       prcm_setup_regs();
+
+       pm_init_serial_console();
+
+       /* Hack to prevent MPU retention when STI console is enabled. */
+       {
+               const struct omap_sti_console_config *sti;
+
+               sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                                     struct omap_sti_console_config);
+               if (sti != NULL && sti->enable)
+                       sti_console_enabled = 1;
+       }
+
+       /*
+        * We copy the assembler sleep/wakeup routines to SRAM.
+        * These routines need to be in SRAM as that's the only
+        * memory the MPU can see when it wakes up.
+        */
+       if (cpu_is_omap24xx()) {
+               omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
+                                                omap24xx_idle_loop_suspend_sz);
+
+               omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
+                                                   omap24xx_cpu_suspend_sz);
+       }
+
+       suspend_set_ops(&omap_pm_ops);
+       pm_idle = omap2_pm_idle;
+
+       return 0;
+}
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644 (file)
index 0000000..a828db6
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * linux/arch/arm/mach-omap2/pm34xx.c
+ *
+ * OMAP3 Power Management Routines
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ * Tony Lindgren <tony@atomide.com>
+ * Jouni Hogander
+ *
+ * Copyright (C) 2005 Texas Instruments, Inc.
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * Based on pm.c for omap1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <mach/gpio.h>
+#include <mach/sram.h>
+#include <mach/pm.h>
+#include <mach/clockdomain.h>
+#include <mach/powerdomain.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm-regbits-34xx.h"
+
+#include "prm.h"
+#include "pm.h"
+#include "smartreflex.h"
+
+struct power_state {
+       struct powerdomain *pwrdm;
+       u32 next_state;
+       u32 saved_state;
+       struct list_head node;
+};
+
+static LIST_HEAD(pwrst_list);
+
+static void (*_omap_sram_idle)(u32 *addr, int save_state);
+
+static void (*saved_idle)(void);
+
+static struct powerdomain *mpu_pwrdm;
+
+/* PRCM Interrupt Handler for wakeups */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+       u32 wkst, irqstatus_mpu;
+       u32 fclk, iclk;
+
+       /* WKUP */
+       wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+       if (wkst) {
+               iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
+               fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
+               cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
+               cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
+               prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
+               while (prm_read_mod_reg(WKUP_MOD, PM_WKST));
+               cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
+               cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+       }
+
+       /* CORE */
+       wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
+       if (wkst) {
+               iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
+               fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
+               prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
+               while (prm_read_mod_reg(CORE_MOD, PM_WKST1));
+               cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
+               cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
+       }
+       wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
+       if (wkst) {
+               iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
+               fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
+               cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+               prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
+               while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3));
+               cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
+               cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
+       }
+
+       /* PER */
+       wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
+       if (wkst) {
+               iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
+               fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
+               cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
+               cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
+               prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
+               while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST));
+               cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
+               cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
+       }
+
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               /* USBHOST */
+               wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
+               if (wkst) {
+                       iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                              CM_ICLKEN);
+                       fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                              CM_FCLKEN);
+                       cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+                                        CM_ICLKEN);
+                       cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
+                                        CM_FCLKEN);
+                       prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
+                                         PM_WKST);
+                       while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                               PM_WKST));
+                       cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
+                                        CM_ICLKEN);
+                       cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
+                                        CM_FCLKEN);
+               }
+       }
+
+       irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+                                       OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+       prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+                                       OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+       while (prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET));
+
+       return IRQ_HANDLED;
+}
+
+static void omap_sram_idle(void)
+{
+       /* Variable to tell what needs to be saved and restored
+        * in omap_sram_idle*/
+       /* save_state = 0 => Nothing to save and restored */
+       /* save_state = 1 => Only L1 and logic lost */
+       /* save_state = 2 => Only L2 lost */
+       /* save_state = 3 => L1, L2 and logic lost */
+       int save_state = 0, mpu_next_state;
+
+       if (!_omap_sram_idle)
+               return;
+
+       mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+       switch (mpu_next_state) {
+       case PWRDM_POWER_RET:
+               /* No need to save context */
+               save_state = 0;
+               break;
+       default:
+               /* Invalid state */
+               printk(KERN_ERR "Invalid mpu state in sram_idle\n");
+               return;
+       }
+       /* Disable smartreflex before entering WFI */
+       disable_smartreflex(SR1);
+       disable_smartreflex(SR2);
+
+       omap2_gpio_prepare_for_retention();
+
+       _omap_sram_idle(NULL, save_state);
+
+       omap2_gpio_resume_after_retention();
+
+       /* Enable smartreflex after WFI */
+       enable_smartreflex(SR1);
+       enable_smartreflex(SR2);
+}
+
+/*
+ * Check if functional clocks are enabled before entering
+ * sleep. This function could be behind CONFIG_PM_DEBUG
+ * when all drivers are configuring their sysconfig registers
+ * properly and using their clocks properly.
+ */
+static int omap3_fclks_active(void)
+{
+       u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
+               fck_cam = 0, fck_per = 0, fck_usbhost = 0;
+
+       fck_core1 = cm_read_mod_reg(CORE_MOD,
+                                   CM_FCLKEN1);
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               fck_core3 = cm_read_mod_reg(CORE_MOD,
+                                           OMAP3430ES2_CM_FCLKEN3);
+               fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
+                                         CM_FCLKEN);
+               fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
+                                             CM_FCLKEN);
+       } else
+               fck_sgx = cm_read_mod_reg(GFX_MOD,
+                                         OMAP3430ES2_CM_FCLKEN3);
+       fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
+                                 CM_FCLKEN);
+       fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
+                                 CM_FCLKEN);
+       fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
+                                 CM_FCLKEN);
+       if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
+           fck_cam | fck_per | fck_usbhost)
+               return 1;
+       return 0;
+}
+
+static int omap3_can_sleep(void)
+{
+       if (!enable_dyn_sleep)
+               return 0;
+       if (omap3_fclks_active())
+               return 0;
+       if (atomic_read(&sleep_block) > 0)
+               return 0;
+       return 1;
+}
+
+/* This sets pwrdm state (other than mpu & core. Currently only ON &
+ * RET are supported. Function is assuming that clkdm doesn't have
+ * hw_sup mode enabled. */
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+{
+       u32 cur_state;
+       int sleep_switch = 0;
+       int ret = 0;
+
+       if (pwrdm == NULL || IS_ERR(pwrdm))
+               return -EINVAL;
+
+       cur_state = pwrdm_read_next_pwrst(pwrdm);
+
+       if (cur_state == state)
+               return ret;
+
+       if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
+               omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
+               sleep_switch = 1;
+               pwrdm_wait_transition(pwrdm);
+       }
+
+       ret = pwrdm_set_next_pwrst(pwrdm, state);
+       if (ret) {
+               printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
+                      pwrdm->name);
+               goto err;
+       }
+
+       if (sleep_switch) {
+               omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+               pwrdm_wait_transition(pwrdm);
+       }
+
+err:
+       return ret;
+}
+
+static void omap3_pm_idle(void)
+{
+       local_irq_disable();
+       local_fiq_disable();
+
+       if (!omap3_can_sleep())
+               goto out;
+
+       if (omap_irq_pending())
+               goto out;
+
+       omap_sram_idle();
+
+out:
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int omap3_pm_prepare(void)
+{
+       saved_idle = pm_idle;
+       pm_idle = NULL;
+       return 0;
+}
+
+static int omap3_pm_suspend(void)
+{
+       struct power_state *pwrst;
+       int state, ret = 0;
+
+       /* Read current next_pwrsts */
+       list_for_each_entry(pwrst, &pwrst_list, node)
+               pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
+       /* Set ones wanted by suspend */
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
+                       goto restore;
+               if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
+                       goto restore;
+       }
+
+       omap_sram_idle();
+
+restore:
+       /* Restore next_pwrsts */
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
+               state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
+               if (state != pwrst->next_state) {
+                       printk(KERN_INFO "Powerdomain (%s) didn't enter "
+                              "target state %d\n",
+                              pwrst->pwrdm->name, pwrst->next_state);
+                       ret = -1;
+               }
+       }
+       if (ret)
+               printk(KERN_ERR "Could not enter target state in pm_suspend\n");
+       else
+               printk(KERN_INFO "Successfully put all powerdomains "
+                      "to target state\n");
+
+       return ret;
+}
+
+static int omap3_pm_enter(suspend_state_t state)
+{
+       int ret = 0;
+
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               ret = omap3_pm_suspend();
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void omap3_pm_finish(void)
+{
+       pm_idle = saved_idle;
+}
+
+static struct platform_suspend_ops omap_pm_ops = {
+       .prepare        = omap3_pm_prepare,
+       .enter          = omap3_pm_enter,
+       .finish         = omap3_pm_finish,
+       .valid          = suspend_valid_only_mem,
+};
+
+static void __init prcm_setup_regs(void)
+{
+       /* XXX Reset all wkdeps. This should be done when initializing
+        * powerdomains */
+       prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
+       prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
+               prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
+       } else
+               prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
+
+       /*
+        * Enable interface clock autoidle for all modules.
+        * Note that in the long run this should be done by clockfw
+        */
+       cm_write_mod_reg(
+               OMAP3430ES2_AUTO_MMC3 |
+               OMAP3430ES2_AUTO_ICR |
+               OMAP3430_AUTO_AES2 |
+               OMAP3430_AUTO_SHA12 |
+               OMAP3430_AUTO_DES2 |
+               OMAP3430_AUTO_MMC2 |
+               OMAP3430_AUTO_MMC1 |
+               OMAP3430_AUTO_MSPRO |
+               OMAP3430_AUTO_HDQ |
+               OMAP3430_AUTO_MCSPI4 |
+               OMAP3430_AUTO_MCSPI3 |
+               OMAP3430_AUTO_MCSPI2 |
+               OMAP3430_AUTO_MCSPI1 |
+               OMAP3430_AUTO_I2C3 |
+               OMAP3430_AUTO_I2C2 |
+               OMAP3430_AUTO_I2C1 |
+               OMAP3430_AUTO_UART2 |
+               OMAP3430_AUTO_UART1 |
+               OMAP3430_AUTO_GPT11 |
+               OMAP3430_AUTO_GPT10 |
+               OMAP3430_AUTO_MCBSP5 |
+               OMAP3430_AUTO_MCBSP1 |
+               OMAP3430ES1_AUTO_FAC | /* This is es1 only */
+               OMAP3430_AUTO_MAILBOXES |
+               OMAP3430_AUTO_OMAPCTRL |
+               OMAP3430ES1_AUTO_FSHOSTUSB |
+               OMAP3430_AUTO_HSOTGUSB |
+               OMAP3430ES1_AUTO_D2D | /* This is es1 only */
+               OMAP3430_AUTO_SSI,
+               CORE_MOD, CM_AUTOIDLE1);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_PKA |
+               OMAP3430_AUTO_AES1 |
+               OMAP3430_AUTO_RNG |
+               OMAP3430_AUTO_SHA11 |
+               OMAP3430_AUTO_DES1,
+               CORE_MOD, CM_AUTOIDLE2);
+
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               cm_write_mod_reg(
+                       OMAP3430ES2_AUTO_USBTLL,
+                       CORE_MOD, CM_AUTOIDLE3);
+       }
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_WDT2 |
+               OMAP3430_AUTO_WDT1 |
+               OMAP3430_AUTO_GPIO1 |
+               OMAP3430_AUTO_32KSYNC |
+               OMAP3430_AUTO_GPT12 |
+               OMAP3430_AUTO_GPT1 ,
+               WKUP_MOD, CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_DSS,
+               OMAP3430_DSS_MOD,
+               CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_CAM,
+               OMAP3430_CAM_MOD,
+               CM_AUTOIDLE);
+
+       cm_write_mod_reg(
+               OMAP3430_AUTO_GPIO6 |
+               OMAP3430_AUTO_GPIO5 |
+               OMAP3430_AUTO_GPIO4 |
+               OMAP3430_AUTO_GPIO3 |
+               OMAP3430_AUTO_GPIO2 |
+               OMAP3430_AUTO_WDT3 |
+               OMAP3430_AUTO_UART3 |
+               OMAP3430_AUTO_GPT9 |
+               OMAP3430_AUTO_GPT8 |
+               OMAP3430_AUTO_GPT7 |
+               OMAP3430_AUTO_GPT6 |
+               OMAP3430_AUTO_GPT5 |
+               OMAP3430_AUTO_GPT4 |
+               OMAP3430_AUTO_GPT3 |
+               OMAP3430_AUTO_GPT2 |
+               OMAP3430_AUTO_MCBSP4 |
+               OMAP3430_AUTO_MCBSP3 |
+               OMAP3430_AUTO_MCBSP2,
+               OMAP3430_PER_MOD,
+               CM_AUTOIDLE);
+
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               cm_write_mod_reg(
+                       OMAP3430ES2_AUTO_USBHOST,
+                       OMAP3430ES2_USBHOST_MOD,
+                       CM_AUTOIDLE);
+       }
+
+       /*
+        * Set all plls to autoidle. This is needed until autoidle is
+        * enabled by clockfw
+        */
+       cm_write_mod_reg(1 << OMAP3430_CLKTRCTRL_IVA2_SHIFT,
+                        OMAP3430_IVA2_MOD,
+                        CM_AUTOIDLE2);
+       cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
+                        MPU_MOD,
+                        CM_AUTOIDLE2);
+       cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
+                        (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
+                        PLL_MOD,
+                        CM_AUTOIDLE);
+       cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
+                        PLL_MOD,
+                        CM_AUTOIDLE2);
+
+       /*
+        * Enable control of expternal oscillator through
+        * sys_clkreq. In the long run clock framework should
+        * take care of this.
+        */
+       prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
+                            1 << OMAP_AUTOEXTCLKMODE_SHIFT,
+                            OMAP3430_GR_MOD,
+                            OMAP3_PRM_CLKSRC_CTRL_OFFSET);
+
+       /* setup wakup source */
+       prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+                         WKUP_MOD, PM_WKEN);
+       /* No need to write EN_IO, that is always enabled */
+       prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1,
+                         WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
+       /* For some reason IO doesn't generate wakeup event even if
+        * it is selected to mpu wakeup goup */
+       prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
+                       OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
+}
+
+static int __init pwrdms_setup(struct powerdomain *pwrdm)
+{
+       struct power_state *pwrst;
+
+       if (!pwrdm->pwrsts)
+               return 0;
+
+       pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+       if (!pwrst)
+               return -ENOMEM;
+       pwrst->pwrdm = pwrdm;
+       pwrst->next_state = PWRDM_POWER_RET;
+       list_add(&pwrst->node, &pwrst_list);
+
+       if (pwrdm_has_hdwr_sar(pwrdm))
+               pwrdm_enable_hdwr_sar(pwrdm);
+
+       return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
+}
+
+static int __init clkdms_setup(struct clockdomain *clkdm)
+{
+       omap2_clkdm_allow_idle(clkdm);
+       return 0;
+}
+
+int __init omap3_pm_init(void)
+{
+       struct power_state *pwrst;
+       int ret;
+
+       printk(KERN_ERR "Power Management for TI OMAP3.\n");
+
+       /* XXX prcm_setup_regs needs to be before enabling hw
+        * supervised mode for powerdomains */
+       prcm_setup_regs();
+
+       ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
+                         (irq_handler_t)prcm_interrupt_handler,
+                         IRQF_DISABLED, "prcm", NULL);
+       if (ret) {
+               printk(KERN_ERR "request_irq failed to register for 0x%x\n",
+                      INT_34XX_PRCM_MPU_IRQ);
+               goto err1;
+       }
+
+       ret = pwrdm_for_each(pwrdms_setup);
+       if (ret) {
+               printk(KERN_ERR "Failed to setup powerdomains\n");
+               goto err2;
+       }
+
+       (void) clkdm_for_each(clkdms_setup);
+
+       mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
+       if (mpu_pwrdm == NULL) {
+               printk(KERN_ERR "Failed to get mpu_pwrdm\n");
+               goto err2;
+       }
+
+       _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
+                                       omap34xx_cpu_suspend_sz);
+
+       suspend_set_ops(&omap_pm_ops);
+
+       pm_idle = omap3_pm_idle;
+
+err1:
+       return ret;
+err2:
+       free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
+       list_for_each_entry(pwrst, &pwrst_list, node) {
+               list_del(&pwrst->node);
+               kfree(pwrst);
+       }
+       return ret;
+}
+
+static void __init configure_vc(void)
+{
+       prm_write_mod_reg((R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA1_SHIFT) |
+                       (R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA0_SHIFT),
+                       OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_SA_OFFSET);
+       prm_write_mod_reg((R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) |
+                       (R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT),
+                       OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET);
+
+       prm_write_mod_reg((OMAP3430_VC_CMD_VAL0_ON <<
+               OMAP3430_VC_CMD_ON_SHIFT) |
+               (OMAP3430_VC_CMD_VAL0_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) |
+               (OMAP3430_VC_CMD_VAL0_RET << OMAP3430_VC_CMD_RET_SHIFT) |
+               (OMAP3430_VC_CMD_VAL0_OFF << OMAP3430_VC_CMD_OFF_SHIFT),
+               OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+
+       prm_write_mod_reg((OMAP3430_VC_CMD_VAL1_ON <<
+               OMAP3430_VC_CMD_ON_SHIFT) |
+               (OMAP3430_VC_CMD_VAL1_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) |
+               (OMAP3430_VC_CMD_VAL1_RET << OMAP3430_VC_CMD_RET_SHIFT) |
+               (OMAP3430_VC_CMD_VAL1_OFF << OMAP3430_VC_CMD_OFF_SHIFT),
+               OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+
+       prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1,
+                               OMAP3430_GR_MOD,
+                               OMAP3_PRM_VC_CH_CONF_OFFSET);
+
+       prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN,
+                               OMAP3430_GR_MOD,
+                               OMAP3_PRM_VC_I2C_CFG_OFFSET);
+
+       /* Setup voltctrl and other setup times */
+
+#ifdef CONFIG_OMAP_SYSOFFMODE
+       prm_write_mod_reg(OMAP3430_AUTO_OFF | OMAP3430_AUTO_RET |
+                       OMAP3430_SEL_OFF, OMAP3430_GR_MOD,
+                       OMAP3_PRM_VOLTCTRL_OFFSET);
+
+       prm_write_mod_reg(OMAP3430_CLKSETUP_DURATION, OMAP3430_GR_MOD,
+                       OMAP3_PRM_CLKSETUP_OFFSET);
+       prm_write_mod_reg((OMAP3430_VOLTSETUP_TIME2 <<
+                       OMAP3430_SETUP_TIME2_SHIFT) |
+                       (OMAP3430_VOLTSETUP_TIME1 <<
+                       OMAP3430_SETUP_TIME1_SHIFT),
+                       OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET);
+
+       prm_write_mod_reg(OMAP3430_VOLTOFFSET_DURATION, OMAP3430_GR_MOD,
+                       OMAP3_PRM_VOLTOFFSET_OFFSET);
+       prm_write_mod_reg(OMAP3430_VOLTSETUP2_DURATION, OMAP3430_GR_MOD,
+                       OMAP3_PRM_VOLTSETUP2_OFFSET);
+#else
+       prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD,
+                       OMAP3_PRM_VOLTCTRL_OFFSET);
+#endif
+
+}
+
+static int __init omap3_pm_early_init(void)
+{
+       prm_clear_mod_reg_bits(OMAP3430_OFFMODE_POL, OMAP3430_GR_MOD,
+                               OMAP3_PRM_POLCTRL_OFFSET);
+
+       configure_vc();
+
+       return 0;
+}
+
+arch_initcall(omap3_pm_early_init);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
new file mode 100644 (file)
index 0000000..73e2971
--- /dev/null
@@ -0,0 +1,1113 @@
+/*
+ * OMAP powerdomain control
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifdef CONFIG_OMAP_DEBUG_POWERDOMAIN
+# define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/atomic.h>
+
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+
+#include <mach/cpu.h>
+#include <mach/powerdomain.h>
+#include <mach/clockdomain.h>
+
+/* pwrdm_list contains all registered struct powerdomains */
+static LIST_HEAD(pwrdm_list);
+
+/*
+ * pwrdm_rwlock protects pwrdm_list add and del ops - also reused to
+ * protect pwrdm_clkdms[] during clkdm add/del ops
+ */
+static DEFINE_RWLOCK(pwrdm_rwlock);
+
+
+/* Private functions */
+
+static u32 prm_read_mod_bits_shift(s16 domain, s16 idx, u32 mask)
+{
+       u32 v;
+
+       v = prm_read_mod_reg(domain, idx);
+       v &= mask;
+       v >>= __ffs(mask);
+
+       return v;
+}
+
+static struct powerdomain *_pwrdm_lookup(const char *name)
+{
+       struct powerdomain *pwrdm, *temp_pwrdm;
+
+       pwrdm = NULL;
+
+       list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+               if (!strcmp(name, temp_pwrdm->name)) {
+                       pwrdm = temp_pwrdm;
+                       break;
+               }
+       }
+
+       return pwrdm;
+}
+
+/* _pwrdm_deps_lookup - look up the specified powerdomain in a pwrdm list */
+static struct powerdomain *_pwrdm_deps_lookup(struct powerdomain *pwrdm,
+                                             struct pwrdm_dep *deps)
+{
+       struct pwrdm_dep *pd;
+
+       if (!pwrdm || !deps || !omap_chip_is(pwrdm->omap_chip))
+               return ERR_PTR(-EINVAL);
+
+       for (pd = deps; pd; pd++) {
+
+               if (!omap_chip_is(pd->omap_chip))
+                       continue;
+
+               if (!pd->pwrdm && pd->pwrdm_name)
+                       pd->pwrdm = pwrdm_lookup(pd->pwrdm_name);
+
+               if (pd->pwrdm == pwrdm)
+                       break;
+
+       }
+
+       if (!pd)
+               return ERR_PTR(-ENOENT);
+
+       return pd->pwrdm;
+}
+
+
+/* Public functions */
+
+/**
+ * pwrdm_init - set up the powerdomain layer
+ *
+ * Loop through the list of powerdomains, registering all that are
+ * available on the current CPU. If pwrdm_list is supplied and not
+ * null, all of the referenced powerdomains will be registered.  No
+ * return value.
+ */
+void pwrdm_init(struct powerdomain **pwrdm_list)
+{
+       struct powerdomain **p = NULL;
+
+       if (pwrdm_list)
+               for (p = pwrdm_list; *p; p++)
+                       pwrdm_register(*p);
+}
+
+/**
+ * pwrdm_register - register a powerdomain
+ * @pwrdm: struct powerdomain * to register
+ *
+ * Adds a powerdomain to the internal powerdomain list.  Returns
+ * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
+ * already registered by the provided name, or 0 upon success.
+ */
+int pwrdm_register(struct powerdomain *pwrdm)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!omap_chip_is(pwrdm->omap_chip))
+               return -EINVAL;
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+       if (_pwrdm_lookup(pwrdm->name)) {
+               ret = -EEXIST;
+               goto pr_unlock;
+       }
+
+       list_add(&pwrdm->node, &pwrdm_list);
+
+       pr_debug("powerdomain: registered %s\n", pwrdm->name);
+       ret = 0;
+
+pr_unlock:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_unregister - unregister a powerdomain
+ * @pwrdm: struct powerdomain * to unregister
+ *
+ * Removes a powerdomain from the internal powerdomain list.  Returns
+ * -EINVAL if pwrdm argument is NULL.
+ */
+int pwrdm_unregister(struct powerdomain *pwrdm)
+{
+       unsigned long flags;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+       list_del(&pwrdm->node);
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       pr_debug("powerdomain: unregistered %s\n", pwrdm->name);
+
+       return 0;
+}
+
+/**
+ * pwrdm_lookup - look up a powerdomain by name, return a pointer
+ * @name: name of powerdomain
+ *
+ * Find a registered powerdomain by its name.  Returns a pointer to the
+ * struct powerdomain if found, or NULL otherwise.
+ */
+struct powerdomain *pwrdm_lookup(const char *name)
+{
+       struct powerdomain *pwrdm;
+       unsigned long flags;
+
+       if (!name)
+               return NULL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+       pwrdm = _pwrdm_lookup(name);
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return pwrdm;
+}
+
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * Call the supplied function for each registered powerdomain.  The
+ * callback function can return anything but 0 to bail out early from
+ * the iterator.  The callback function is called with the pwrdm_rwlock
+ * held for reading, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware
+ * powerdomain control functions are fine.  Returns the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure; or -EINVAL if the function
+ * pointer is null.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm))
+{
+       struct powerdomain *temp_pwrdm;
+       unsigned long flags;
+       int ret = 0;
+
+       if (!fn)
+               return -EINVAL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+       list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
+               ret = (*fn)(temp_pwrdm);
+               if (ret)
+                       break;
+       }
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_add_clkdm - add a clockdomain to a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'.  This
+ * enables the use of pwrdm_for_each_clkdm().  Returns -EINVAL if
+ * presented with invalid pointers; -ENOMEM if memory could not be allocated;
+ * or 0 upon success.
+ */
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+       unsigned long flags;
+       int i;
+       int ret = -EINVAL;
+
+       if (!pwrdm || !clkdm)
+               return -EINVAL;
+
+       pr_debug("powerdomain: associating clockdomain %s with powerdomain "
+                "%s\n", clkdm->name, pwrdm->name);
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
+               if (!pwrdm->pwrdm_clkdms[i])
+                       break;
+#ifdef DEBUG
+               if (pwrdm->pwrdm_clkdms[i] == clkdm) {
+                       ret = -EINVAL;
+                       goto pac_exit;
+               }
+#endif
+       }
+
+       if (i == PWRDM_MAX_CLKDMS) {
+               pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for "
+                        "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name);
+               WARN_ON(1);
+               ret = -ENOMEM;
+               goto pac_exit;
+       }
+
+       pwrdm->pwrdm_clkdms[i] = clkdm;
+
+       ret = 0;
+
+pac_exit:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_del_clkdm - remove a clockdomain from a powerdomain
+ * @pwrdm: struct powerdomain * to add the clockdomain to
+ * @clkdm: struct clockdomain * to associate with a powerdomain
+ *
+ * Dissociate the clockdomain 'clkdm' from the powerdomain
+ * 'pwrdm'. Returns -EINVAL if presented with invalid pointers;
+ * -ENOENT if the clkdm was not associated with the powerdomain, or 0
+ * upon success.
+ */
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
+{
+       unsigned long flags;
+       int ret = -EINVAL;
+       int i;
+
+       if (!pwrdm || !clkdm)
+               return -EINVAL;
+
+       pr_debug("powerdomain: dissociating clockdomain %s from powerdomain "
+                "%s\n", clkdm->name, pwrdm->name);
+
+       write_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS; i++)
+               if (pwrdm->pwrdm_clkdms[i] == clkdm)
+                       break;
+
+       if (i == PWRDM_MAX_CLKDMS) {
+               pr_debug("powerdomain: clkdm %s not associated with pwrdm "
+                        "%s ?!\n", clkdm->name, pwrdm->name);
+               ret = -ENOENT;
+               goto pdc_exit;
+       }
+
+       pwrdm->pwrdm_clkdms[i] = NULL;
+
+       ret = 0;
+
+pdc_exit:
+       write_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+/**
+ * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm
+ * @pwrdm: struct powerdomain * to iterate over
+ * @fn: callback function *
+ *
+ * Call the supplied function for each clockdomain in the powerdomain
+ * 'pwrdm'.  The callback function can return anything but 0 to bail
+ * out early from the iterator.  The callback function is called with
+ * the pwrdm_rwlock held for reading, so no powerdomain structure
+ * manipulation functions should be called from the callback, although
+ * hardware powerdomain control functions are fine.  Returns -EINVAL
+ * if presented with invalid pointers; or passes along the last return
+ * value of the callback function, which should be 0 for success or
+ * anything else to indicate failure.
+ */
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+                        int (*fn)(struct powerdomain *pwrdm,
+                                  struct clockdomain *clkdm))
+{
+       unsigned long flags;
+       int ret = 0;
+       int i;
+
+       if (!fn)
+               return -EINVAL;
+
+       read_lock_irqsave(&pwrdm_rwlock, flags);
+
+       for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++)
+               ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]);
+
+       read_unlock_irqrestore(&pwrdm_rwlock, flags);
+
+       return ret;
+}
+
+
+/**
+ * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * When the powerdomain represented by pwrdm2 wakes up (due to an
+ * interrupt), wake up pwrdm1. Implemented in hardware on the OMAP,
+ * this feature is designed to reduce wakeup latency of the dependent
+ * powerdomain.  Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: hardware will wake up %s when %s wakes up\n",
+                pwrdm1->name, pwrdm2->name);
+
+       prm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+                            pwrdm1->prcm_offs, PM_WKDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_del_wkdep - remove a wakeup dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Remove a wakeup dependency that causes pwrdm1 to wake up when pwrdm2
+ * wakes up.  Returns -EINVAL if presented with invalid powerdomain
+ * pointers, -ENOENT if pwrdm2 cannot wake up pwrdm1 in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: hardware will no longer wake up %s after %s "
+                "wakes up\n", pwrdm1->name, pwrdm2->name);
+
+       prm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+                              pwrdm1->prcm_offs, PM_WKDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_wkdep - read wakeup dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: wake this struct powerdomain * up (dependent)
+ * @pwrdm2: when this struct powerdomain * wakes up (source)
+ *
+ * Return 1 if a hardware wakeup dependency exists wherein pwrdm1 will be
+ * awoken when pwrdm2 wakes up; 0 if dependency is not set; -EINVAL
+ * if either powerdomain pointer is invalid; or -ENOENT if the hardware
+ * is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * wakeup dependencies.  Wakeup dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->wkdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear wake up of "
+                        "%s when %s wakes up\n", pwrdm1->name, pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       return prm_read_mod_bits_shift(pwrdm1->prcm_offs, PM_WKDEP,
+                                       (1 << pwrdm2->dep_bit));
+}
+
+/**
+ * pwrdm_add_sleepdep - add a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Prevent pwrdm1 from automatically going inactive (and then to
+ * retention or off) if pwrdm2 is still active.         Returns -EINVAL if
+ * presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be set in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: will prevent %s from sleeping if %s is active\n",
+                pwrdm1->name, pwrdm2->name);
+
+       cm_set_mod_reg_bits((1 << pwrdm2->dep_bit),
+                           pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_del_sleepdep - remove a sleep dependency from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Allow pwrdm1 to automatically go inactive (and then to retention or
+ * off), independent of the activity state of pwrdm2.  Returns -EINVAL
+ * if presented with invalid powerdomain pointers or called on a machine
+ * that does not support software-configurable hardware sleep dependencies,
+ * -ENOENT if the specified dependency cannot be cleared in hardware, or
+ * 0 upon success.
+ */
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       pr_debug("powerdomain: will no longer prevent %s from sleeping if "
+                "%s is active\n", pwrdm1->name, pwrdm2->name);
+
+       cm_clear_mod_reg_bits((1 << pwrdm2->dep_bit),
+                             pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_sleepdep - read sleep dependency state from pwrdm2 to pwrdm1
+ * @pwrdm1: prevent this struct powerdomain * from sleeping (dependent)
+ * @pwrdm2: when this struct powerdomain * is active (source)
+ *
+ * Return 1 if a hardware sleep dependency exists wherein pwrdm1 will
+ * not be allowed to automatically go inactive if pwrdm2 is active;
+ * 0 if pwrdm1's automatic power state inactivity transition is independent
+ * of pwrdm2's; -EINVAL if either powerdomain pointer is invalid or called
+ * on a machine that does not support software-configurable hardware sleep
+ * dependencies; or -ENOENT if the hardware is incapable.
+ *
+ * REVISIT: Currently this function only represents software-controllable
+ * sleep dependencies. Sleep dependencies fixed in hardware are not
+ * yet handled here.
+ */
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2)
+{
+       struct powerdomain *p;
+
+       if (!pwrdm1)
+               return -EINVAL;
+
+       if (!cpu_is_omap34xx())
+               return -EINVAL;
+
+       p = _pwrdm_deps_lookup(pwrdm2, pwrdm1->sleepdep_srcs);
+       if (IS_ERR(p)) {
+               pr_debug("powerdomain: hardware cannot set/clear sleep "
+                        "dependency affecting %s from %s\n", pwrdm1->name,
+                        pwrdm2->name);
+               return IS_ERR(p);
+       }
+
+       return prm_read_mod_bits_shift(pwrdm1->prcm_offs, OMAP3430_CM_SLEEPDEP,
+                                       (1 << pwrdm2->dep_bit));
+}
+
+/**
+ * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain
+ * @pwrdm: struct powerdomain *
+ *
+ * Return the number of controllable memory banks in powerdomain pwrdm,
+ * starting with 1.  Returns -EINVAL if the powerdomain pointer is null.
+ */
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return pwrdm->banks;
+}
+
+/**
+ * pwrdm_set_next_pwrst - set next powerdomain power state
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the powerdomain pwrdm's next power state to pwrst.  The powerdomain
+ * may not enter this state immediately if the preconditions for this state
+ * have not been satisfied.  Returns -EINVAL if the powerdomain pointer is
+ * null or if the power state is invalid for the powerdomin, or returns 0
+ * upon success.
+ */
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->pwrsts & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
+                pwrdm->name, pwrst);
+
+       prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
+                            (pwrst << OMAP_POWERSTATE_SHIFT),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_next_pwrst - get next powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's next power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the next power state
+ * upon success.
+ */
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
+                                       OMAP_POWERSTATE_MASK);
+}
+
+/**
+ * pwrdm_read_pwrst - get current powerdomain power state
+ * @pwrdm: struct powerdomain * to get power state
+ *
+ * Return the powerdomain pwrdm's current power state. Returns -EINVAL
+ * if the powerdomain pointer is null or returns the current power state
+ * upon success.
+ */
+int pwrdm_read_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+                                       OMAP_POWERSTATEST_MASK);
+}
+
+/**
+ * pwrdm_read_prev_pwrst - get previous powerdomain power state
+ * @pwrdm: struct powerdomain * to get previous power state
+ *
+ * Return the powerdomain pwrdm's previous power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous power state
+ * upon success.
+ */
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+                                       OMAP3430_LASTPOWERSTATEENTERED_MASK);
+}
+
+/**
+ * pwrdm_set_logic_retst - set powerdomain logic power state upon retention
+ * @pwrdm: struct powerdomain * to set
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that the logic portion of the powerdomain
+ * pwrdm will enter when the powerdomain enters retention.  This will
+ * be either RETENTION or OFF, if supported.  Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported, or returns 0 upon success.
+ */
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->pwrsts_logic_ret & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next logic powerstate for %s to %0x\n",
+                pwrdm->name, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       prm_rmw_mod_reg_bits(OMAP3430_LOGICL1CACHERETSTATE,
+                            (pwrst << __ffs(OMAP3430_LOGICL1CACHERETSTATE)),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_set_mem_onst - set memory power state while powerdomain ON
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the ON state.  Bank
+ * will be a number from 0 to 3, and represents different types of
+ * memory, depending on the powerdomain.  Returns -EINVAL if the
+ * powerdomain pointer is null or the target power state is not not
+ * supported for this memory bank, -EEXIST if the target memory bank
+ * does not exist or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       if (!(pwrdm->pwrsts_mem_on[bank] & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next memory powerstate for domain %s "
+                "bank %0x while pwrdm-ON to %0x\n", pwrdm->name, bank, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATONSTATE_MASK;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMONSTATE_MASK;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATONSTATE_MASK;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMONSTATE_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)),
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_set_mem_retst - set memory power state while powerdomain in RET
+ * @pwrdm: struct powerdomain * to set
+ * @bank: memory bank number to set (0-3)
+ * @pwrst: one of the PWRDM_POWER_* macros
+ *
+ * Set the next power state that memory bank x of the powerdomain
+ * pwrdm will enter when the powerdomain enters the RETENTION state.
+ * Bank will be a number from 0 to 3, and represents different types
+ * of memory, depending on the powerdomain.  pwrst will be either
+ * RETENTION or OFF, if supported. Returns -EINVAL if the powerdomain
+ * pointer is null or the target power state is not not supported for
+ * this memory bank, -EEXIST if the target memory bank does not exist
+ * or is not controllable, or returns 0 upon success.
+ */
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       if (!(pwrdm->pwrsts_mem_ret[bank] & (1 << pwrst)))
+               return -EINVAL;
+
+       pr_debug("powerdomain: setting next memory powerstate for domain %s "
+                "bank %0x while pwrdm-RET to %0x\n", pwrdm->name, bank, pwrst);
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMRETSTATE;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMRETSTATE;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       prm_rmw_mod_reg_bits(m, (pwrst << __ffs(m)), pwrdm->prcm_offs,
+                            PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_read_logic_pwrst - get current powerdomain logic retention power state
+ * @pwrdm: struct powerdomain * to get current logic retention power state
+ *
+ * Return the current power state that the logic portion of
+ * powerdomain pwrdm will enter
+ * Returns -EINVAL if the powerdomain pointer is null or returns the
+ * current logic retention power state upon success.
+ */
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST,
+                                       OMAP3430_LOGICSTATEST);
+}
+
+/**
+ * pwrdm_read_prev_logic_pwrst - get previous powerdomain logic power state
+ * @pwrdm: struct powerdomain * to get previous logic power state
+ *
+ * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the previous logic
+ * power state upon success.
+ */
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST,
+                                       OMAP3430_LASTLOGICSTATEENTERED);
+}
+
+/**
+ * pwrdm_read_mem_pwrst - get current memory bank power state
+ * @pwrdm: struct powerdomain * to get current memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's current memory power state for bank
+ * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the current memory power state upon success.
+ */
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_SHAREDL1CACHEFLATSTATEST_MASK;
+               break;
+       case 1:
+               m = OMAP3430_L1FLATMEMSTATEST_MASK;
+               break;
+       case 2:
+               m = OMAP3430_SHAREDL2CACHEFLATSTATEST_MASK;
+               break;
+       case 3:
+               m = OMAP3430_L2FLATMEMSTATEST_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTST, m);
+}
+
+/**
+ * pwrdm_read_prev_mem_pwrst - get previous memory bank power state
+ * @pwrdm: struct powerdomain * to get previous memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's previous memory power state for bank
+ * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the previous memory power state upon success.
+ */
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+       u32 m;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (pwrdm->banks < (bank + 1))
+               return -EEXIST;
+
+       /*
+        * The register bit names below may not correspond to the
+        * actual names of the bits in each powerdomain's register,
+        * but the type of value returned is the same for each
+        * powerdomain.
+        */
+       switch (bank) {
+       case 0:
+               m = OMAP3430_LASTMEM1STATEENTERED_MASK;
+               break;
+       case 1:
+               m = OMAP3430_LASTMEM2STATEENTERED_MASK;
+               break;
+       case 2:
+               m = OMAP3430_LASTSHAREDL2CACHEFLATSTATEENTERED_MASK;
+               break;
+       case 3:
+               m = OMAP3430_LASTL2FLATMEMSTATEENTERED_MASK;
+               break;
+       default:
+               WARN_ON(1); /* should never happen */
+               return -EEXIST;
+       }
+
+       return prm_read_mod_bits_shift(pwrdm->prcm_offs,
+                                       OMAP3430_PM_PREPWSTST, m);
+}
+
+/**
+ * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
+ * @pwrdm: struct powerdomain * to clear
+ *
+ * Clear the powerdomain's previous power state register.  Clears the
+ * entire register, including logic and memory bank previous power states.
+ * Returns -EINVAL if the powerdomain pointer is null, or returns 0 upon
+ * success.
+ */
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * XXX should get the powerdomain's current state here;
+        * warn & fail if it is not ON.
+        */
+
+       pr_debug("powerdomain: clearing previous power state reg for %s\n",
+                pwrdm->name);
+
+       prm_write_mod_reg(0, pwrdm->prcm_offs, OMAP3430_PM_PREPWSTST);
+
+       return 0;
+}
+
+/**
+ * pwrdm_enable_hdwr_sar - enable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
+ *
+ * Enable automatic context save-and-restore upon power state change
+ * for some devices in a powerdomain.  Warning: this only affects a
+ * subset of devices in a powerdomain; check the TRM closely.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the powerdomain
+ * does not support automatic save-and-restore, or returns 0 upon
+ * success.
+ */
+int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+               return -EINVAL;
+
+       pr_debug("powerdomain: %s: setting SAVEANDRESTORE bit\n",
+                pwrdm->name);
+
+       prm_rmw_mod_reg_bits(0, 1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT,
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_disable_hdwr_sar - disable automatic hardware SAR for a pwrdm
+ * @pwrdm: struct powerdomain *
+ *
+ * Disable automatic context save-and-restore upon power state change
+ * for some devices in a powerdomain.  Warning: this only affects a
+ * subset of devices in a powerdomain; check the TRM closely.  Returns
+ * -EINVAL if the powerdomain pointer is null or if the powerdomain
+ * does not support automatic save-and-restore, or returns 0 upon
+ * success.
+ */
+int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm)
+{
+       if (!pwrdm)
+               return -EINVAL;
+
+       if (!(pwrdm->flags & PWRDM_HAS_HDWR_SAR))
+               return -EINVAL;
+
+       pr_debug("powerdomain: %s: clearing SAVEANDRESTORE bit\n",
+                pwrdm->name);
+
+       prm_rmw_mod_reg_bits(1 << OMAP3430ES2_SAVEANDRESTORE_SHIFT, 0,
+                            pwrdm->prcm_offs, PM_PWSTCTRL);
+
+       return 0;
+}
+
+/**
+ * pwrdm_has_hdwr_sar - test whether powerdomain supports hardware SAR
+ * @pwrdm: struct powerdomain *
+ *
+ * Returns 1 if powerdomain 'pwrdm' supports hardware save-and-restore
+ * for some devices, or 0 if it does not.
+ */
+bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
+{
+       return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
+}
+
+/**
+ * pwrdm_wait_transition - wait for powerdomain power transition to finish
+ * @pwrdm: struct powerdomain * to wait for
+ *
+ * If the powerdomain pwrdm is in the process of a state transition,
+ * spin until it completes the power transition, or until an iteration
+ * bailout value is reached. Returns -EINVAL if the powerdomain
+ * pointer is null, -EAGAIN if the bailout value was reached, or
+ * returns 0 upon success.
+ */
+int pwrdm_wait_transition(struct powerdomain *pwrdm)
+{
+       u32 c = 0;
+
+       if (!pwrdm)
+               return -EINVAL;
+
+       /*
+        * REVISIT: pwrdm_wait_transition() may be better implemented
+        * via a callback and a periodic timer check -- how long do we expect
+        * powerdomain transitions to take?
+        */
+
+       /* XXX Is this udelay() value meaningful? */
+       while ((prm_read_mod_reg(pwrdm->prcm_offs, PM_PWSTST) &
+               OMAP_INTRANSITION) &&
+              (c++ < PWRDM_TRANSITION_BAILOUT))
+               udelay(1);
+
+       if (c >= PWRDM_TRANSITION_BAILOUT) {
+               printk(KERN_ERR "powerdomain: waited too long for "
+                      "powerdomain %s to complete transition\n", pwrdm->name);
+               return -EAGAIN;
+       }
+
+       pr_debug("powerdomain: completed transition in %d loops\n", c);
+
+       return 0;
+}
+
+
diff --git a/arch/arm/mach-omap2/powerdomains.h b/arch/arm/mach-omap2/powerdomains.h
new file mode 100644 (file)
index 0000000..51623e2
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * OMAP2/3 common powerdomain definitions
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS
+
+/*
+ * This file contains all of the powerdomains that have some element
+ * of software control for the OMAP24xx and OMAP34XX chips.
+ *
+ * A few notes:
+ *
+ * This is not an exhaustive listing of powerdomains on the chips; only
+ * powerdomains that can be controlled in software.
+ *
+ * A useful validation rule for struct powerdomain:
+ * Any powerdomain referenced by a wkdep_srcs or sleepdep_srcs array
+ * must have a dep_bit assigned.  So wkdep_srcs/sleepdep_srcs are really
+ * just software-controllable dependencies.  Non-software-controllable
+ * dependencies do exist, but they are not encoded below (yet).
+ *
+ * 24xx does not support programmable sleep dependencies (SLEEPDEP)
+ *
+ */
+
+/*
+ * The names for the DSP/IVA2 powerdomains are confusing.
+ *
+ * Most OMAP chips have an on-board DSP.
+ *
+ * On the 2420, this is a 'C55 DSP called, simply, the DSP.  Its
+ * powerdomain is called the "DSP power domain."  On the 2430, the
+ * on-board DSP is a 'C64 DSP, now called the IVA2 or IVA2.1.  Its
+ * powerdomain is still called the "DSP power domain." On the 3430,
+ * the DSP is a 'C64 DSP like the 2430, also known as the IVA2; but
+ * its powerdomain is now called the "IVA2 power domain."
+ *
+ * The 2420 also has something called the IVA, which is a separate ARM
+ * core, and has nothing to do with the DSP/IVA2.
+ *
+ * Ideally the DSP/IVA2 could just be the same powerdomain, but the PRCM
+ * address offset is different between the C55 and C64 DSPs.
+ *
+ * The overly-specific dep_bit names are due to a bit name collision
+ * with CM_FCLKEN_{DSP,IVA2}.  The DSP/IVA2 PM_WKDEP and CM_SLEEPDEP shift
+ * value are the same for all powerdomains: 2
+ */
+
+/*
+ * XXX should dep_bit be a mask, so we can test to see if it is 0 as a
+ * sanity check?
+ * XXX encode hardware fixed wakeup dependencies -- esp. for 3430 CORE
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "cm.h"
+
+/* OMAP2/3-common powerdomains and wakeup dependencies */
+
+/*
+ * 2420/2430 PM_WKDEP_GFX: CORE, MPU, WKUP
+ * 3430ES1 PM_WKDEP_GFX: adds IVA2, removes CORE
+ * 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE
+ */
+static struct pwrdm_dep gfx_sgx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                           CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                           CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430: CM_SLEEPDEP_CAM: MPU
+ * 3430ES1: CM_SLEEPDEP_GFX: MPU
+ * 3430ES2: CM_SLEEPDEP_SGX: MPU
+ */
+static struct pwrdm_dep cam_gfx_sleepdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+#include "powerdomains24xx.h"
+#include "powerdomains34xx.h"
+
+
+/*
+ * OMAP2/3 common powerdomains
+ */
+
+/*
+ * The GFX powerdomain is not present on 3430ES2, but currently we do not
+ * have a macro to filter it out at compile-time.
+ */
+static struct powerdomain gfx_pwrdm = {
+       .name             = "gfx_pwrdm",
+       .prcm_offs        = GFX_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX |
+                                          CHIP_IS_OMAP3430ES1),
+       .wkdep_srcs       = gfx_sgx_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain wkup_pwrdm = {
+       .name           = "wkup_pwrdm",
+       .prcm_offs      = WKUP_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX | CHIP_IS_OMAP3430),
+       .dep_bit        = OMAP_EN_WKUP_SHIFT,
+};
+
+
+
+/* As powerdomains are added or removed above, this list must also be changed */
+static struct powerdomain *powerdomains_omap[] __initdata = {
+
+       &gfx_pwrdm,
+       &wkup_pwrdm,
+
+#ifdef CONFIG_ARCH_OMAP24XX
+       &dsp_pwrdm,
+       &mpu_24xx_pwrdm,
+       &core_24xx_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2430
+       &mdm_pwrdm,
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+       &iva2_pwrdm,
+       &mpu_34xx_pwrdm,
+       &neon_pwrdm,
+       &core_34xx_es1_pwrdm,
+       &core_34xx_es2_pwrdm,
+       &cam_pwrdm,
+       &dss_pwrdm,
+       &per_pwrdm,
+       &emu_pwrdm,
+       &sgx_pwrdm,
+       &usbhost_pwrdm,
+       &dpll1_pwrdm,
+       &dpll2_pwrdm,
+       &dpll3_pwrdm,
+       &dpll4_pwrdm,
+       &dpll5_pwrdm,
+#endif
+
+       NULL
+};
+
+
+#endif
diff --git a/arch/arm/mach-omap2/powerdomains24xx.h b/arch/arm/mach-omap2/powerdomains24xx.h
new file mode 100644 (file)
index 0000000..9f08dc3
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * OMAP24XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS24XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-24xx.h"
+#include "cm.h"
+#include "cm-regbits-24xx.h"
+
+/* 24XX powerdomains and dependencies */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+
+/* Wakeup dependency source arrays */
+
+/*
+ * 2420/2430 PM_WKDEP_DSP: CORE, MPU, WKUP
+ * 2430 PM_WKDEP_MDM: same as above
+ */
+static struct pwrdm_dep dsp_mdm_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_MPU: CORE, DSP, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep mpu_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "dsp_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mdm_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+       },
+       { NULL },
+};
+
+/*
+ * 2420 PM_WKDEP_CORE: DSP, GFX, MPU, WKUP
+ * 2430 adds MDM
+ */
+static struct pwrdm_dep core_24xx_wkdeps[] = {
+       {
+               .pwrdm_name = "dsp_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "gfx_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX)
+       },
+       {
+               .pwrdm_name = "mdm_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
+       },
+       { NULL },
+};
+
+
+/* Powerdomains */
+
+static struct powerdomain dsp_pwrdm = {
+       .name             = "dsp_pwrdm",
+       .prcm_offs        = OMAP24XX_DSP_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .dep_bit          = OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT,
+       .wkdep_srcs       = dsp_mdm_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain mpu_24xx_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = MPU_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .dep_bit          = OMAP24XX_EN_MPU_SHIFT,
+       .wkdep_srcs       = mpu_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain core_24xx_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP24XX),
+       .wkdep_srcs       = core_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .dep_bit          = OMAP24XX_EN_CORE_SHIFT,
+       .banks            = 3,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,    /* MEM1RETSTATE */
+               [1] = PWRSTS_OFF_RET,    /* MEM2RETSTATE */
+               [2] = PWRSTS_OFF_RET,    /* MEM3RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+               [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */
+       },
+};
+
+#endif    /* CONFIG_ARCH_OMAP24XX */
+
+
+
+/*
+ * 2430-specific powerdomains
+ */
+
+#ifdef CONFIG_ARCH_OMAP2430
+
+/* XXX 2430 KILLDOMAINWKUP bit?  No current users apparently */
+
+/* Another case of bit name collisions between several registers: EN_MDM */
+static struct powerdomain mdm_pwrdm = {
+       .name             = "mdm_pwrdm",
+       .prcm_offs        = OMAP2430_MDM_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+       .dep_bit          = OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT,
+       .wkdep_srcs       = dsp_mdm_24xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+#endif     /* CONFIG_ARCH_OMAP2430 */
+
+
+#endif
diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h
new file mode 100644 (file)
index 0000000..446a1ed
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * OMAP34XX powerdomain definitions
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ * Debugging and integration fixes by Jouni Högander
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+#define ARCH_ARM_MACH_OMAP2_POWERDOMAINS34XX
+
+/*
+ * N.B. If powerdomains are added or removed from this file, update
+ * the array in mach-omap2/powerdomains.h.
+ */
+
+#include <mach/powerdomain.h>
+
+#include "prcm-common.h"
+#include "prm.h"
+#include "prm-regbits-34xx.h"
+#include "cm.h"
+#include "cm-regbits-34xx.h"
+
+/*
+ * 34XX-specific powerdomains, dependencies
+ */
+
+#ifdef CONFIG_ARCH_OMAP34XX
+
+/*
+ * 3430: PM_WKDEP_{PER,USBHOST}: CORE, IVA2, MPU, WKUP
+ * (USBHOST is ES2 only)
+ */
+static struct pwrdm_dep per_usbhost_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_MPU: CORE, IVA2, DSS, PER
+ */
+static struct pwrdm_dep mpu_34xx_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "dss_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "per_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/*
+ * 3430 PM_WKDEP_IVA2: CORE, MPU, WKUP, DSS, PER
+ */
+static struct pwrdm_dep iva2_wkdeps[] = {
+       {
+               .pwrdm_name = "core_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "dss_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "per_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/* 3430 PM_WKDEP_{CAM,DSS}: IVA2, MPU, WKUP */
+static struct pwrdm_dep cam_dss_wkdeps[] = {
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "wkup_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+/* 3430: PM_WKDEP_NEON: MPU */
+static struct pwrdm_dep neon_wkdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/* Sleep dependency source arrays for 34xx-specific pwrdms - 34XX only */
+
+/*
+ * 3430: CM_SLEEPDEP_{DSS,PER}: MPU, IVA
+ * 3430ES2: CM_SLEEPDEP_USBHOST: MPU, IVA
+ */
+static struct pwrdm_dep dss_per_usbhost_sleepdeps[] = {
+       {
+               .pwrdm_name = "mpu_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       {
+               .pwrdm_name = "iva2_pwrdm",
+               .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
+       },
+       { NULL },
+};
+
+
+/*
+ * Powerdomains
+ */
+
+static struct powerdomain iva2_pwrdm = {
+       .name             = "iva2_pwrdm",
+       .prcm_offs        = OMAP3430_IVA2_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT,
+       .wkdep_srcs       = iva2_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 4,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,
+               [1] = PWRSTS_OFF_RET,
+               [2] = PWRSTS_OFF_RET,
+               [3] = PWRSTS_OFF_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,
+               [1] = PWRDM_POWER_ON,
+               [2] = PWRSTS_OFF_ON,
+               [3] = PWRDM_POWER_ON,
+       },
+};
+
+static struct powerdomain mpu_34xx_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = MPU_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_EN_MPU_SHIFT,
+       .wkdep_srcs       = mpu_34xx_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_ON,
+       },
+};
+
+/* No wkdeps or sleepdeps for 34xx core apparently */
+static struct powerdomain core_34xx_es1_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .dep_bit          = OMAP3430_EN_CORE_SHIFT,
+       .banks            = 2,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,    /* MEM1RETSTATE */
+               [1] = PWRSTS_OFF_RET,    /* MEM2RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+       },
+};
+
+/* No wkdeps or sleepdeps for 34xx core apparently */
+static struct powerdomain core_34xx_es2_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = CORE_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .dep_bit          = OMAP3430_EN_CORE_SHIFT,
+       .flags            = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
+       .banks            = 2,
+       .pwrsts_mem_ret   = {
+               [0] = PWRSTS_OFF_RET,    /* MEM1RETSTATE */
+               [1] = PWRSTS_OFF_RET,    /* MEM2RETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
+               [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+       },
+};
+
+/* Another case of bit name collisions between several registers: EN_DSS */
+static struct powerdomain dss_pwrdm = {
+       .name             = "dss_pwrdm",
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .prcm_offs        = OMAP3430_DSS_MOD,
+       .dep_bit          = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
+       .wkdep_srcs       = cam_dss_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain sgx_pwrdm = {
+       .name             = "sgx_pwrdm",
+       .prcm_offs        = OMAP3430ES2_SGX_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+       .wkdep_srcs       = gfx_sgx_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       /* XXX This is accurate for 3430 SGX, but what about GFX? */
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain cam_pwrdm = {
+       .name             = "cam_pwrdm",
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .prcm_offs        = OMAP3430_CAM_MOD,
+       .wkdep_srcs       = cam_dss_wkdeps,
+       .sleepdep_srcs    = cam_gfx_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain per_pwrdm = {
+       .name             = "per_pwrdm",
+       .prcm_offs        = OMAP3430_PER_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .dep_bit          = OMAP3430_EN_PER_SHIFT,
+       .wkdep_srcs       = per_usbhost_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain emu_pwrdm = {
+       .name           = "emu_pwrdm",
+       .prcm_offs      = OMAP3430_EMU_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain neon_pwrdm = {
+       .name             = "neon_pwrdm",
+       .prcm_offs        = OMAP3430_NEON_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+       .wkdep_srcs       = neon_wkdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+};
+
+static struct powerdomain usbhost_pwrdm = {
+       .name             = "usbhost_pwrdm",
+       .prcm_offs        = OMAP3430ES2_USBHOST_MOD,
+       .omap_chip        = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+       .wkdep_srcs       = per_usbhost_wkdeps,
+       .sleepdep_srcs    = dss_per_usbhost_sleepdeps,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRDM_POWER_RET,
+       .flags            = PWRDM_HAS_HDWR_SAR, /* for USBHOST ctrlr only */
+       .banks            = 1,
+       .pwrsts_mem_ret   = {
+               [0] = PWRDM_POWER_RET, /* MEMRETSTATE */
+       },
+       .pwrsts_mem_on    = {
+               [0] = PWRDM_POWER_ON,  /* MEMONSTATE */
+       },
+};
+
+static struct powerdomain dpll1_pwrdm = {
+       .name           = "dpll1_pwrdm",
+       .prcm_offs      = MPU_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll2_pwrdm = {
+       .name           = "dpll2_pwrdm",
+       .prcm_offs      = OMAP3430_IVA2_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll3_pwrdm = {
+       .name           = "dpll3_pwrdm",
+       .prcm_offs      = PLL_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll4_pwrdm = {
+       .name           = "dpll4_pwrdm",
+       .prcm_offs      = PLL_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+static struct powerdomain dpll5_pwrdm = {
+       .name           = "dpll5_pwrdm",
+       .prcm_offs      = PLL_MOD,
+       .omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES2),
+};
+
+
+#endif    /* CONFIG_ARCH_OMAP34XX */
+
+
+#endif
index 54c32f482131819666dc81c79a2b5661ae43d515..812d50ee495d5d3201d718373612a593ecc1fdcf 100644 (file)
 #define OMAP2430_EN_USBHS                              (1 << 6)
 
 /* CM_IDLEST1_CORE, PM_WKST1_CORE shared bits */
-#define OMAP2420_ST_MMC                                        (1 << 26)
-#define OMAP24XX_ST_UART2                              (1 << 22)
-#define OMAP24XX_ST_UART1                              (1 << 21)
-#define OMAP24XX_ST_MCSPI2                             (1 << 18)
-#define OMAP24XX_ST_MCSPI1                             (1 << 17)
-#define OMAP24XX_ST_GPT12                              (1 << 14)
-#define OMAP24XX_ST_GPT11                              (1 << 13)
-#define OMAP24XX_ST_GPT10                              (1 << 12)
-#define OMAP24XX_ST_GPT9                               (1 << 11)
-#define OMAP24XX_ST_GPT8                               (1 << 10)
-#define OMAP24XX_ST_GPT7                               (1 << 9)
-#define OMAP24XX_ST_GPT6                               (1 << 8)
-#define OMAP24XX_ST_GPT5                               (1 << 7)
-#define OMAP24XX_ST_GPT4                               (1 << 6)
-#define OMAP24XX_ST_GPT3                               (1 << 5)
-#define OMAP24XX_ST_GPT2                               (1 << 4)
-#define OMAP2420_ST_VLYNQ                              (1 << 3)
+#define OMAP2420_ST_MMC_SHIFT                          26
+#define OMAP2420_ST_MMC_MASK                           (1 << 26)
+#define OMAP24XX_ST_UART2_SHIFT                                22
+#define OMAP24XX_ST_UART2_MASK                         (1 << 22)
+#define OMAP24XX_ST_UART1_SHIFT                                21
+#define OMAP24XX_ST_UART1_MASK                         (1 << 21)
+#define OMAP24XX_ST_MCSPI2_SHIFT                       18
+#define OMAP24XX_ST_MCSPI2_MASK                                (1 << 18)
+#define OMAP24XX_ST_MCSPI1_SHIFT                       17
+#define OMAP24XX_ST_MCSPI1_MASK                                (1 << 17)
+#define OMAP24XX_ST_GPT12_SHIFT                                14
+#define OMAP24XX_ST_GPT12_MASK                         (1 << 14)
+#define OMAP24XX_ST_GPT11_SHIFT                                13
+#define OMAP24XX_ST_GPT11_MASK                         (1 << 13)
+#define OMAP24XX_ST_GPT10_SHIFT                                12
+#define OMAP24XX_ST_GPT10_MASK                         (1 << 12)
+#define OMAP24XX_ST_GPT9_SHIFT                         11
+#define OMAP24XX_ST_GPT9_MASK                          (1 << 11)
+#define OMAP24XX_ST_GPT8_SHIFT                         10
+#define OMAP24XX_ST_GPT8_MASK                          (1 << 10)
+#define OMAP24XX_ST_GPT7_SHIFT                         9
+#define OMAP24XX_ST_GPT7_MASK                          (1 << 9)
+#define OMAP24XX_ST_GPT6_SHIFT                         8
+#define OMAP24XX_ST_GPT6_MASK                          (1 << 8)
+#define OMAP24XX_ST_GPT5_SHIFT                         7
+#define OMAP24XX_ST_GPT5_MASK                          (1 << 7)
+#define OMAP24XX_ST_GPT4_SHIFT                         6
+#define OMAP24XX_ST_GPT4_MASK                          (1 << 6)
+#define OMAP24XX_ST_GPT3_SHIFT                         5
+#define OMAP24XX_ST_GPT3_MASK                          (1 << 5)
+#define OMAP24XX_ST_GPT2_SHIFT                         4
+#define OMAP24XX_ST_GPT2_MASK                          (1 << 4)
+#define OMAP2420_ST_VLYNQ_SHIFT                                3
+#define OMAP2420_ST_VLYNQ_MASK                         (1 << 3)
 
 /* CM_IDLEST2_CORE, PM_WKST2_CORE shared bits */
-#define OMAP2430_ST_MDM_INTC                           (1 << 11)
-#define OMAP2430_ST_GPIO5                              (1 << 10)
-#define OMAP2430_ST_MCSPI3                             (1 << 9)
-#define OMAP2430_ST_MMCHS2                             (1 << 8)
-#define OMAP2430_ST_MMCHS1                             (1 << 7)
-#define OMAP2430_ST_USBHS                              (1 << 6)
-#define OMAP24XX_ST_UART3                              (1 << 2)
-#define OMAP24XX_ST_USB                                        (1 << 0)
+#define OMAP2430_ST_MDM_INTC_SHIFT                     11
+#define OMAP2430_ST_MDM_INTC_MASK                      (1 << 11)
+#define OMAP2430_ST_GPIO5_SHIFT                                10
+#define OMAP2430_ST_GPIO5_MASK                         (1 << 10)
+#define OMAP2430_ST_MCSPI3_SHIFT                       9
+#define OMAP2430_ST_MCSPI3_MASK                                (1 << 9)
+#define OMAP2430_ST_MMCHS2_SHIFT                       8
+#define OMAP2430_ST_MMCHS2_MASK                                (1 << 8)
+#define OMAP2430_ST_MMCHS1_SHIFT                       7
+#define OMAP2430_ST_MMCHS1_MASK                                (1 << 7)
+#define OMAP2430_ST_USBHS_SHIFT                                6
+#define OMAP2430_ST_USBHS_MASK                         (1 << 6)
+#define OMAP24XX_ST_UART3_SHIFT                                2
+#define OMAP24XX_ST_UART3_MASK                         (1 << 2)
+#define OMAP24XX_ST_USB_SHIFT                          0
+#define OMAP24XX_ST_USB_MASK                           (1 << 0)
 
 /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
 #define OMAP24XX_EN_GPIOS_SHIFT                                2
 #define OMAP24XX_EN_GPT1                               (1 << 0)
 
 /* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
-#define OMAP24XX_ST_GPIOS                              (1 << 2)
-#define OMAP24XX_ST_GPT1                               (1 << 0)
+#define OMAP24XX_ST_GPIOS_SHIFT                                (1 << 2)
+#define OMAP24XX_ST_GPIOS_MASK                         2
+#define OMAP24XX_ST_GPT1_SHIFT                         (1 << 0)
+#define OMAP24XX_ST_GPT1_MASK                          0
 
 /* CM_IDLEST_MDM and PM_WKST_MDM shared bits */
-#define OMAP2430_ST_MDM                                        (1 << 0)
+#define OMAP2430_ST_MDM_SHIFT                          (1 << 0)
 
 
 /* 3430 register bits shared between CM & PRM registers */
 #define OMAP3430_EN_HSOTGUSB_SHIFT                             4
 
 /* PM_WKST1_CORE, CM_IDLEST1_CORE shared bits */
-#define OMAP3430_ST_MMC2                               (1 << 25)
-#define OMAP3430_ST_MMC1                               (1 << 24)
-#define OMAP3430_ST_MCSPI4                             (1 << 21)
-#define OMAP3430_ST_MCSPI3                             (1 << 20)
-#define OMAP3430_ST_MCSPI2                             (1 << 19)
-#define OMAP3430_ST_MCSPI1                             (1 << 18)
-#define OMAP3430_ST_I2C3                               (1 << 17)
-#define OMAP3430_ST_I2C2                               (1 << 16)
-#define OMAP3430_ST_I2C1                               (1 << 15)
-#define OMAP3430_ST_UART2                              (1 << 14)
-#define OMAP3430_ST_UART1                              (1 << 13)
-#define OMAP3430_ST_GPT11                              (1 << 12)
-#define OMAP3430_ST_GPT10                              (1 << 11)
-#define OMAP3430_ST_MCBSP5                             (1 << 10)
-#define OMAP3430_ST_MCBSP1                             (1 << 9)
-#define OMAP3430_ST_FSHOSTUSB                          (1 << 5)
-#define OMAP3430_ST_HSOTGUSB                           (1 << 4)
-#define OMAP3430_ST_D2D                                        (1 << 3)
+#define OMAP3430_ST_MMC2_SHIFT                         25
+#define OMAP3430_ST_MMC2_MASK                          (1 << 25)
+#define OMAP3430_ST_MMC1_SHIFT                         24
+#define OMAP3430_ST_MMC1_MASK                          (1 << 24)
+#define OMAP3430_ST_MCSPI4_SHIFT                       21
+#define OMAP3430_ST_MCSPI4_MASK                                (1 << 21)
+#define OMAP3430_ST_MCSPI3_SHIFT                       20
+#define OMAP3430_ST_MCSPI3_MASK                                (1 << 20)
+#define OMAP3430_ST_MCSPI2_SHIFT                       19
+#define OMAP3430_ST_MCSPI2_MASK                                (1 << 19)
+#define OMAP3430_ST_MCSPI1_SHIFT                       18
+#define OMAP3430_ST_MCSPI1_MASK                                (1 << 18)
+#define OMAP3430_ST_I2C3_SHIFT                         17
+#define OMAP3430_ST_I2C3_MASK                          (1 << 17)
+#define OMAP3430_ST_I2C2_SHIFT                         16
+#define OMAP3430_ST_I2C2_MASK                          (1 << 16)
+#define OMAP3430_ST_I2C1_SHIFT                         15
+#define OMAP3430_ST_I2C1_MASK                          (1 << 15)
+#define OMAP3430_ST_UART2_SHIFT                                14
+#define OMAP3430_ST_UART2_MASK                         (1 << 14)
+#define OMAP3430_ST_UART1_SHIFT                                13
+#define OMAP3430_ST_UART1_MASK                         (1 << 13)
+#define OMAP3430_ST_GPT11_SHIFT                                12
+#define OMAP3430_ST_GPT11_MASK                         (1 << 12)
+#define OMAP3430_ST_GPT10_SHIFT                                11
+#define OMAP3430_ST_GPT10_MASK                         (1 << 11)
+#define OMAP3430_ST_MCBSP5_SHIFT                       10
+#define OMAP3430_ST_MCBSP5_MASK                                (1 << 10)
+#define OMAP3430_ST_MCBSP1_SHIFT                       9
+#define OMAP3430_ST_MCBSP1_MASK                                (1 << 9)
+#define OMAP3430ES1_ST_FSHOSTUSB_SHIFT                 5
+#define OMAP3430ES1_ST_FSHOSTUSB_MASK                  (1 << 5)
+#define OMAP3430ES1_ST_HSOTGUSB_SHIFT                  4
+#define OMAP3430ES1_ST_HSOTGUSB_MASK                   (1 << 4)
+#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT             5
+#define OMAP3430ES2_ST_HSOTGUSB_IDLE_MASK              (1 << 5)
+#define OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT            4
+#define OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK             (1 << 4)
+#define OMAP3430_ST_D2D_SHIFT                          3
+#define OMAP3430_ST_D2D_MASK                           (1 << 3)
 
 /* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
 #define OMAP3430_EN_GPIO1                              (1 << 3)
 #define OMAP3430_EN_GPT12_SHIFT                                1
 
 /* CM_IDLEST_WKUP, PM_WKST_WKUP shared bits */
-#define OMAP3430_ST_SR2                                        (1 << 7)
-#define OMAP3430_ST_SR1                                        (1 << 6)
-#define OMAP3430_ST_GPIO1                              (1 << 3)
-#define OMAP3430_ST_GPT12                              (1 << 1)
-#define OMAP3430_ST_GPT1                               (1 << 0)
+#define OMAP3430_ST_SR2_SHIFT                          7
+#define OMAP3430_ST_SR2_MASK                           (1 << 7)
+#define OMAP3430_ST_SR1_SHIFT                          6
+#define OMAP3430_ST_SR1_MASK                           (1 << 6)
+#define OMAP3430_ST_GPIO1_SHIFT                                3
+#define OMAP3430_ST_GPIO1_MASK                         (1 << 3)
+#define OMAP3430_ST_GPT12_SHIFT                                1
+#define OMAP3430_ST_GPT12_MASK                         (1 << 1)
+#define OMAP3430_ST_GPT1_SHIFT                         0
+#define OMAP3430_ST_GPT1_MASK                          (1 << 0)
 
 /*
  * CM_SLEEPDEP_GFX, CM_SLEEPDEP_DSS, CM_SLEEPDEP_CAM,
 #define OMAP3430_EN_MCBSP2_SHIFT                       0
 
 /* CM_IDLEST_PER, PM_WKST_PER shared bits */
-#define OMAP3430_ST_GPIO6                              (1 << 17)
-#define OMAP3430_ST_GPIO5                              (1 << 16)
-#define OMAP3430_ST_GPIO4                              (1 << 15)
-#define OMAP3430_ST_GPIO3                              (1 << 14)
-#define OMAP3430_ST_GPIO2                              (1 << 13)
-#define OMAP3430_ST_UART3                              (1 << 11)
-#define OMAP3430_ST_GPT9                               (1 << 10)
-#define OMAP3430_ST_GPT8                               (1 << 9)
-#define OMAP3430_ST_GPT7                               (1 << 8)
-#define OMAP3430_ST_GPT6                               (1 << 7)
-#define OMAP3430_ST_GPT5                               (1 << 6)
-#define OMAP3430_ST_GPT4                               (1 << 5)
-#define OMAP3430_ST_GPT3                               (1 << 4)
-#define OMAP3430_ST_GPT2                               (1 << 3)
+#define OMAP3430_ST_GPIO6_SHIFT                                17
+#define OMAP3430_ST_GPIO6_MASK                         (1 << 17)
+#define OMAP3430_ST_GPIO5_SHIFT                                16
+#define OMAP3430_ST_GPIO5_MASK                         (1 << 16)
+#define OMAP3430_ST_GPIO4_SHIFT                                15
+#define OMAP3430_ST_GPIO4_MASK                         (1 << 15)
+#define OMAP3430_ST_GPIO3_SHIFT                                14
+#define OMAP3430_ST_GPIO3_MASK                         (1 << 14)
+#define OMAP3430_ST_GPIO2_SHIFT                                13
+#define OMAP3430_ST_GPIO2_MASK                         (1 << 13)
+#define OMAP3430_ST_UART3_SHIFT                                11
+#define OMAP3430_ST_UART3_MASK                         (1 << 11)
+#define OMAP3430_ST_GPT9_SHIFT                         10
+#define OMAP3430_ST_GPT9_MASK                          (1 << 10)
+#define OMAP3430_ST_GPT8_SHIFT                         9
+#define OMAP3430_ST_GPT8_MASK                          (1 << 9)
+#define OMAP3430_ST_GPT7_SHIFT                         8
+#define OMAP3430_ST_GPT7_MASK                          (1 << 8)
+#define OMAP3430_ST_GPT6_SHIFT                         7
+#define OMAP3430_ST_GPT6_MASK                          (1 << 7)
+#define OMAP3430_ST_GPT5_SHIFT                         6
+#define OMAP3430_ST_GPT5_MASK                          (1 << 6)
+#define OMAP3430_ST_GPT4_SHIFT                         5
+#define OMAP3430_ST_GPT4_MASK                          (1 << 5)
+#define OMAP3430_ST_GPT3_SHIFT                         4
+#define OMAP3430_ST_GPT3_MASK                          (1 << 4)
+#define OMAP3430_ST_GPT2_SHIFT                         3
+#define OMAP3430_ST_GPT2_MASK                          (1 << 3)
 
 /* CM_SLEEPDEP_PER, PM_WKDEP_IVA2, PM_WKDEP_MPU, PM_WKDEP_PER shared bits */
-#define OMAP3430_EN_CORE                               (1 << 0)
+#define OMAP3430_EN_CORE_SHIFT                         0
+#define OMAP3430_EN_CORE_MASK                          (1 << 0)
 
 #endif
 
index c6d17a3378ec3035c683920136f49f3395053829..4002051c20b98457bdc12142e8d328d33fedc4a4 100644 (file)
 #define OMAP24XX_WKUP1_EN                              (1 << 0)
 
 /* PM_WKDEP_GFX, PM_WKDEP_MPU, PM_WKDEP_DSP, PM_WKDEP_MDM shared bits */
-#define OMAP24XX_EN_MPU                                        (1 << 1)
-#define OMAP24XX_EN_CORE                               (1 << 0)
+#define OMAP24XX_EN_MPU_SHIFT                          1
+#define OMAP24XX_EN_MPU_MASK                           (1 << 1)
+#define OMAP24XX_EN_CORE_SHIFT                                 0
+#define OMAP24XX_EN_CORE_MASK                          (1 << 0)
 
 /*
  * PM_PWSTCTRL_MPU, PM_PWSTCTRL_GFX, PM_PWSTCTRL_DSP, PM_PWSTCTRL_MDM
 /* 2430 calls GLOBALWMPU_RST "GLOBALWARM_RST" instead */
 
 /* PM_WKDEP_MPU specific bits */
-#define OMAP2430_PM_WKDEP_MPU_EN_MDM                   (1 << 5)
-#define OMAP24XX_PM_WKDEP_MPU_EN_DSP                   (1 << 2)
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_SHIFT             5
+#define OMAP2430_PM_WKDEP_MPU_EN_MDM_MASK              (1 << 5)
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_SHIFT             2
+#define OMAP24XX_PM_WKDEP_MPU_EN_DSP_MASK              (1 << 2)
 
 /* PM_EVGENCTRL_MPU specific bits */
 
index b4686bc345ca661bbe58c07d7d6ac4469f9b427c..f82b5a71b01041e67ec09dbea6da556513df0836 100644 (file)
@@ -68,7 +68,8 @@
 #define OMAP3430_VPINIDLE                              (1 << 0)
 
 /* PM_WKDEP_IVA2, PM_WKDEP_MPU shared bits */
-#define OMAP3430_EN_PER                                        (1 << 7)
+#define OMAP3430_EN_PER_SHIFT                          7
+#define OMAP3430_EN_PER_MASK                           (1 << 7)
 
 /* PM_PWSTCTRL_IVA2, PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE shared bits */
 #define OMAP3430_MEMORYCHANGE                          (1 << 3)
@@ -77,7 +78,7 @@
 #define OMAP3430_LOGICSTATEST                          (1 << 2)
 
 /* PM_PREPWSTST_IVA2, PM_PREPWSTST_CORE shared bits */
-#define OMAP3430_LASTLOGICSTATEENTERED                         (1 << 2)
+#define OMAP3430_LASTLOGICSTATEENTERED                 (1 << 2)
 
 /*
  * PM_PREPWSTST_IVA2, PM_PREPWSTST_MPU, PM_PREPWSTST_CORE,
 #define OMAP3430_EMULATION_MPU_RST                     (1 << 11)
 
 /* PM_WKDEP_MPU specific bits */
-#define OMAP3430_PM_WKDEP_MPU_EN_DSS                   (1 << 5)
-#define OMAP3430_PM_WKDEP_MPU_EN_IVA2                  (1 << 2)
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT             5
+#define OMAP3430_PM_WKDEP_MPU_EN_DSS_MASK              (1 << 5)
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT            2
+#define OMAP3430_PM_WKDEP_MPU_EN_IVA2_MASK             (1 << 2)
 
 /* PM_EVGENCTRL_MPU */
 #define OMAP3430_OFFLOADMODE_SHIFT                     3
 
 /* PM_WKEN_WKUP specific bits */
 #define OMAP3430_EN_IO                                 (1 << 8)
+#define OMAP3430_EN_GPIO1                              (1 << 3)
 
 /* PM_MPUGRPSEL_WKUP specific bits */
 
 /* PM_PWSTST_EMU specific bits */
 
 /* PRM_VC_SMPS_SA */
-#define OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT              16
-#define OMAP3430_PRM_VC_SMPS_SA_SA1_MASK               (0x7f << 16)
-#define OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT              0
-#define OMAP3430_PRM_VC_SMPS_SA_SA0_MASK               (0x7f << 0)
+#define OMAP3430_SMPS_SA1_SHIFT                                16
+#define OMAP3430_SMPS_SA1_MASK                         (0x7f << 16)
+#define OMAP3430_SMPS_SA0_SHIFT                                0
+#define OMAP3430_SMPS_SA0_MASK                         (0x7f << 0)
 
 /* PRM_VC_SMPS_VOL_RA */
 #define OMAP3430_VOLRA1_SHIFT                          16
 #define OMAP3430_CMDRA0_SHIFT                          0
 #define OMAP3430_CMDRA0_MASK                           (0xff << 0)
 
+/* PRM_VC_CMD_VAL */
+#define OMAP3430_VC_CMD_ON_SHIFT                       24
+#define OMAP3430_VC_CMD_ON_MASK                                (0xFF << 24)
+#define OMAP3430_VC_CMD_ONLP_SHIFT                     16
+#define OMAP3430_VC_CMD_ONLP_MASK                      (0xFF << 16)
+#define OMAP3430_VC_CMD_RET_SHIFT                      8
+#define OMAP3430_VC_CMD_RET_MASK                       (0xFF << 8)
+#define OMAP3430_VC_CMD_OFF_SHIFT                      0
+#define OMAP3430_VC_CMD_OFF_MASK                       (0xFF << 0)
+
 /* PRM_VC_CMD_VAL_0 specific bits */
+#define OMAP3430_VC_CMD_VAL0_ON                                (0x3 << 4)
+#define OMAP3430_VC_CMD_VAL0_ONLP                      (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL0_RET                       (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL0_OFF                       (0x3 << 3)
 
 /* PRM_VC_CMD_VAL_1 specific bits */
+#define OMAP3430_VC_CMD_VAL1_ON                                (0xB << 2)
+#define OMAP3430_VC_CMD_VAL1_ONLP                      (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL1_RET                       (0x3 << 3)
+#define OMAP3430_VC_CMD_VAL1_OFF                       (0x3 << 3)
 
 /* PRM_VC_CH_CONF */
 #define OMAP3430_CMD1                                  (1 << 20)
 #define OMAP3430_AUTO_RET                              (1 << 1)
 #define OMAP3430_AUTO_SLEEP                            (1 << 0)
 
+/* Constants to define setup durations */
+#define OMAP3430_CLKSETUP_DURATION                     0xff
+#define OMAP3430_VOLTSETUP_TIME2                       0xfff
+#define OMAP3430_VOLTSETUP_TIME1                       0xfff
+#define OMAP3430_VOLTOFFSET_DURATION                   0xff
+#define OMAP3430_VOLTSETUP2_DURATION                   0xff
+
 /* PRM_SRAM_PCHARGE */
 #define OMAP3430_PCHARGE_TIME_SHIFT                    0
 #define OMAP3430_PCHARGE_TIME_MASK                     (0xff << 0)
index bbf41fc8e9a9102cd70003b59fb7c85615f4339e..3c6418e8e71a74745944fe84120482e9148f58ce 100644 (file)
@@ -4,8 +4,8 @@
 /*
  * OMAP2/3 Power/Reset Management (PRM) register definitions
  *
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
  *
  * Written by Paul Walmsley
  *
 
 #include "prcm-common.h"
 
-#ifndef __ASSEMBLER__
-#define OMAP_PRM_REGADDR(module, reg)                                  \
-       (void __iomem *)IO_ADDRESS(OMAP2_PRM_BASE + (module) + (reg))
-#else
 #define OMAP2420_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP2420_PRM_BASE + (module) + (reg))
 #define OMAP2430_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP2430_PRM_BASE + (module) + (reg))
 #define OMAP34XX_PRM_REGADDR(module, reg)                              \
                        IO_ADDRESS(OMAP3430_PRM_BASE + (module) + (reg))
-#endif
 
 /*
  * Architecture-specific global PRM registers
- * Use __raw_{read,write}l() with these registers.
+ * Use prm_{read,write}_mod_reg() with these registers.
  *
  * With a few exceptions, these are the register names beginning with
  * PRCM_* on 24xx, and PRM_* on 34xx.  (The exceptions are the
  *
  */
 
-/* Global 24xx registers in GR_MOD (Same as OCP_MOD for 24xx) */
+/* Common registers for 24xx and 34xx in OCP_MOD */
+#define OMAP2_PRM_IRQSTATUS_MPU_OFFSET         0x0018
+#define OMAP2_PRM_IRQENABLE_MPU_OFFSET         0x001c
+
+/* 24xx register offsets in OCP_MOD */
+#define OMAP24XX_PRM_REVISION_OFFSET           0x0000
+#define OMAP24XX_PRM_SYSCONFIG_OFFSET          0x0010
+
+/* 34xx register offsets in OCP_MOD */
+#define OMAP3430_PRM_REVISION_OFFSET           0x0004
+#define OMAP3430_PRM_SYSCONFIG_OFFSET          0x0014
+
+/* 24xx register offsets in OMAP24XX_GR_MOD (Same as OCP_MOD for 24xx) */
 #define OMAP24XX_PRCM_VOLTCTRL_OFFSET          0x0050
+#define OMAP24XX_PRCM_VOLTST_OFFSET            0x0054
+#define OMAP24XX_PRCM_CLKSRC_CTRL_OFFSET       0x0060
+#define OMAP24XX_PRCM_CLKOUT_CTRL_OFFSET       0x0070
+#define OMAP24XX_PRCM_CLKEMUL_CTRL_OFFSET      0x0078
 #define OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET       0x0080
-
-/* 242x GR_MOD registers, use these only for assembly code */
-#define OMAP242X_PRCM_VOLTCTRL         OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP242X_PRCM_CLKCFG_CTRL      OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* 243x GR_MOD registers, use these only for assembly code */
-#define OMAP243X_PRCM_VOLTCTRL         OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
-#define OMAP243X_PRCM_CLKCFG_CTRL      OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
-                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
-
-/* These will disappear */
-#define OMAP24XX_PRCM_REVISION         OMAP_PRM_REGADDR(OCP_MOD, 0x0000)
-#define OMAP24XX_PRCM_SYSCONFIG                OMAP_PRM_REGADDR(OCP_MOD, 0x0010)
-
-#define OMAP24XX_PRCM_IRQSTATUS_MPU    OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP24XX_PRCM_IRQENABLE_MPU    OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
-#define OMAP24XX_PRCM_VOLTST           OMAP_PRM_REGADDR(OCP_MOD, 0x0054)
-#define OMAP24XX_PRCM_CLKSRC_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0060)
-#define OMAP24XX_PRCM_CLKOUT_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0070)
-#define OMAP24XX_PRCM_CLKEMUL_CTRL     OMAP_PRM_REGADDR(OCP_MOD, 0x0078)
-#define OMAP24XX_PRCM_CLKCFG_CTRL      OMAP_PRM_REGADDR(OCP_MOD, 0x0080)
-#define OMAP24XX_PRCM_CLKCFG_STATUS    OMAP_PRM_REGADDR(OCP_MOD, 0x0084)
-#define OMAP24XX_PRCM_VOLTSETUP                OMAP_PRM_REGADDR(OCP_MOD, 0x0090)
-#define OMAP24XX_PRCM_CLKSSETUP                OMAP_PRM_REGADDR(OCP_MOD, 0x0094)
-#define OMAP24XX_PRCM_POLCTRL          OMAP_PRM_REGADDR(OCP_MOD, 0x0098)
-
-#define OMAP3430_PRM_REVISION          OMAP_PRM_REGADDR(OCP_MOD, 0x0004)
-#define OMAP3430_PRM_SYSCONFIG         OMAP_PRM_REGADDR(OCP_MOD, 0x0014)
-
-#define OMAP3430_PRM_IRQSTATUS_MPU     OMAP_PRM_REGADDR(OCP_MOD, 0x0018)
-#define OMAP3430_PRM_IRQENABLE_MPU     OMAP_PRM_REGADDR(OCP_MOD, 0x001c)
-
-
-#define OMAP3430_PRM_VC_SMPS_SA                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0020)
-#define OMAP3430_PRM_VC_SMPS_VOL_RA    OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0024)
-#define OMAP3430_PRM_VC_SMPS_CMD_RA    OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0028)
-#define OMAP3430_PRM_VC_CMD_VAL_0      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x002c)
-#define OMAP3430_PRM_VC_CMD_VAL_1      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0030)
-#define OMAP3430_PRM_VC_CH_CONF                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0034)
-#define OMAP3430_PRM_VC_I2C_CFG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0038)
-#define OMAP3430_PRM_VC_BYPASS_VAL     OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x003c)
-#define OMAP3430_PRM_RSTCTRL           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0050)
-#define OMAP3430_PRM_RSTTIME           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0054)
-#define OMAP3430_PRM_RSTST             OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0058)
-#define OMAP3430_PRM_VOLTCTRL          OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0060)
-#define OMAP3430_PRM_SRAM_PCHARGE      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0064)
-#define OMAP3430_PRM_CLKSRC_CTRL       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0070)
-#define OMAP3430_PRM_VOLTSETUP1                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0090)
-#define OMAP3430_PRM_VOLTOFFSET                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0094)
-#define OMAP3430_PRM_CLKSETUP          OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x0098)
-#define OMAP3430_PRM_POLCTRL           OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x009c)
-#define OMAP3430_PRM_VOLTSETUP2                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00a0)
-#define OMAP3430_PRM_VP1_CONFIG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b0)
-#define OMAP3430_PRM_VP1_VSTEPMIN      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b4)
-#define OMAP3430_PRM_VP1_VSTEPMAX      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00b8)
-#define OMAP3430_PRM_VP1_VLIMITTO      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00bc)
-#define OMAP3430_PRM_VP1_VOLTAGE       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c0)
-#define OMAP3430_PRM_VP1_STATUS                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00c4)
-#define OMAP3430_PRM_VP2_CONFIG                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d0)
-#define OMAP3430_PRM_VP2_VSTEPMIN      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d4)
-#define OMAP3430_PRM_VP2_VSTEPMAX      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00d8)
-#define OMAP3430_PRM_VP2_VLIMITTO      OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00dc)
-#define OMAP3430_PRM_VP2_VOLTAGE       OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
-#define OMAP3430_PRM_VP2_STATUS                OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
-
-#define OMAP3430_PRM_CLKSEL            OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
-#define OMAP3430_PRM_CLKOUT_CTRL       OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
+#define OMAP24XX_PRCM_CLKCFG_STATUS_OFFSET     0x0084
+#define OMAP24XX_PRCM_VOLTSETUP_OFFSET         0x0090
+#define OMAP24XX_PRCM_CLKSSETUP_OFFSET         0x0094
+#define OMAP24XX_PRCM_POLCTRL_OFFSET           0x0098
+
+/* 34xx register offsets in GR_MOD */
+#define OMAP3_PRM_VC_SMPS_SA_OFFSET            0x0020
+#define OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET                0x0024
+#define OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET                0x0028
+#define OMAP3_PRM_VC_CMD_VAL_0_OFFSET          0x002c
+#define OMAP3_PRM_VC_CMD_VAL_1_OFFSET          0x0030
+#define OMAP3_PRM_VC_CH_CONF_OFFSET            0x0034
+#define OMAP3_PRM_VC_I2C_CFG_OFFSET            0x0038
+#define OMAP3_PRM_VC_BYPASS_VAL_OFFSET         0x003c
+#define OMAP3_PRM_RSTCTRL_OFFSET               0x0050
+#define OMAP3_PRM_RSTTIME_OFFSET               0x0054
+#define OMAP3_PRM_RSTST_OFFSET                 0x0058
+#define OMAP3_PRM_VOLTCTRL_OFFSET              0x0060
+#define OMAP3_PRM_SRAM_PCHARGE_OFFSET          0x0064
+#define OMAP3_PRM_CLKSRC_CTRL_OFFSET           0x0070
+#define OMAP3_PRM_VOLTSETUP1_OFFSET            0x0090
+#define OMAP3_PRM_VOLTOFFSET_OFFSET            0x0094
+#define OMAP3_PRM_CLKSETUP_OFFSET              0x0098
+#define OMAP3_PRM_POLCTRL_OFFSET               0x009c
+#define OMAP3_PRM_VOLTSETUP2_OFFSET            0x00a0
+#define OMAP3_PRM_VP1_CONFIG_OFFSET            0x00b0
+#define OMAP3_PRM_VP1_VSTEPMIN_OFFSET          0x00b4
+#define OMAP3_PRM_VP1_VSTEPMAX_OFFSET          0x00b8
+#define OMAP3_PRM_VP1_VLIMITTO_OFFSET          0x00bc
+#define OMAP3_PRM_VP1_VOLTAGE_OFFSET           0x00c0
+#define OMAP3_PRM_VP1_STATUS_OFFSET            0x00c4
+#define OMAP3_PRM_VP2_CONFIG_OFFSET            0x00d0
+#define OMAP3_PRM_VP2_VSTEPMIN_OFFSET          0x00d4
+#define OMAP3_PRM_VP2_VSTEPMAX_OFFSET          0x00d8
+#define OMAP3_PRM_VP2_VLIMITTO_OFFSET          0x00dc
+#define OMAP3_PRM_VP2_VOLTAGE_OFFSET           0x00e0
+#define OMAP3_PRM_VP2_STATUS_OFFSET            0x00e4
+
+/* 34xx register offsets in CCR_MOD */
+#define OMAP3_PRM_CLKSEL_OFFSET                        0x0040
+#define OMAP3_PRM_CLKOUT_CTRL_OFFSET           0x0070
 
 /*
  * Module specific PRM registers from PRM_BASE + domain offset
 #define PM_PWSTCTRL                                    0x00e0
 #define PM_PWSTST                                      0x00e4
 
+/* Omap2 specific registers */
+#define OMAP24XX_PM_WKEN2                              0x00a4
+#define OMAP24XX_PM_WKST2                              0x00b4
+
+#define OMAP24XX_PRCM_IRQSTATUS_DSP                    0x00f0  /* IVA mod */
+#define OMAP24XX_PRCM_IRQENABLE_DSP                    0x00f4  /* IVA mod */
+#define OMAP24XX_PRCM_IRQSTATUS_IVA                    0x00f8
+#define OMAP24XX_PRCM_IRQENABLE_IVA                    0x00fc
+
+/* Omap3 specific registers */
+#define OMAP3430ES2_PM_WKEN3                           0x00f0
+#define OMAP3430ES2_PM_WKST3                           0x00b8
+
 #define OMAP3430_PM_MPUGRPSEL                          0x00a4
 #define OMAP3430_PM_MPUGRPSEL1                         OMAP3430_PM_MPUGRPSEL
 
 #define OMAP3430_PRM_IRQSTATUS_IVA2                    0x00f8
 #define OMAP3430_PRM_IRQENABLE_IVA2                    0x00fc
 
-
-/* Architecture-specific registers */
-
-#define OMAP24XX_PM_WKEN2                              0x00a4
-#define OMAP24XX_PM_WKST2                              0x00b4
-
-#define OMAP24XX_PRCM_IRQSTATUS_DSP                    0x00f0  /* IVA mod */
-#define OMAP24XX_PRCM_IRQENABLE_DSP                    0x00f4  /* IVA mod */
-#define OMAP24XX_PRCM_IRQSTATUS_IVA                    0x00f8
-#define OMAP24XX_PRCM_IRQENABLE_IVA                    0x00fc
-
 #ifndef __ASSEMBLER__
 
 /* Power/reset management domain register get/set */
@@ -228,7 +211,6 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
 #define OMAP_RSTTIME1_SHIFT                            0
 #define OMAP_RSTTIME1_MASK                             (0xff << 0)
 
-
 /* PRM_RSTCTRL */
 /* Named RM_RSTCTRL_WKUP on the 24xx */
 /* 2420 calls RST_DPLL3 'RST_DPLL' */
@@ -305,7 +287,8 @@ static inline u32 prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
  * 3430: PM_WKDEP_IVA2, PM_WKDEP_GFX, PM_WKDEP_DSS, PM_WKDEP_CAM,
  *      PM_WKDEP_PER
  */
-#define OMAP_EN_WKUP                                   (1 << 4)
+#define OMAP_EN_WKUP_SHIFT                             4
+#define OMAP_EN_WKUP_MASK                              (1 << 4)
 
 /*
  * 24XX: PM_PWSTCTRL_MPU, PM_PWSTCTRL_CORE, PM_PWSTCTRL_GFX,
diff --git a/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h b/arch/arm/mach-omap2/sdram-micron-mt46h32m32lf-6.h
new file mode 100644 (file)
index 0000000..ef35415
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Micron MT46H32M32LF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+#define ARCH_ARM_MACH_OMAP2_SDRAM_MICRON_MT46H32M32LF
+
+#include <mach/sdrc.h>
+
+/* Micron MT46H32M32LF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params mt46h32m32lf6_sdrc_params[] = {
+       [0] = {
+               .rate        = 165941176,
+               .actim_ctrla = 0x9a9db4c6,
+               .actim_ctrlb = 0x00011217,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [1] = {
+               .rate        = 133333333,
+               .actim_ctrla = 0x7a19b485,
+               .actim_ctrlb = 0x00011213,
+               .rfr_ctrl    = 0x0003de01,
+               .mr          = 0x00000032,
+       },
+       [2] = {
+               .rate        = 82970588,
+               .actim_ctrla = 0x51512283,
+               .actim_ctrlb = 0x0001120c,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000032,
+       },
+       [3] = {
+               .rate        = 66666666,
+               .actim_ctrla = 0x410d2243,
+               .actim_ctrlb = 0x0001120a,
+               .rfr_ctrl    = 0x0001d601,
+               .mr          = 0x00000032,
+       },
+       [4] = {
+               .rate        = 0
+       },
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h b/arch/arm/mach-omap2/sdram-qimonda-hyb18m512160af-6.h
new file mode 100644 (file)
index 0000000..74a92c8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Qimonda HYB18M512160AF-6
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+#define ARCH_ARM_MACH_OMAP2_SDRAM_QIMONDA_HYB18M512160AF6
+
+#include <mach/sdrc.h>
+
+/* Qimonda HYB18M512160AF-6 */
+/* XXX Using ARE = 0x1 (no autorefresh burst) -- can this be changed? */
+static struct omap_sdrc_params hyb18m512160af6_sdrc_params[] = {
+       [0] = {
+               .rate        = 165941176,
+               .actim_ctrla = 0x629db4c6,
+               .actim_ctrlb = 0x00012214,
+               .rfr_ctrl    = 0x0004dc01,
+               .mr          = 0x00000032,
+       },
+       [1] = {
+               .rate        = 133333333,
+               .actim_ctrla = 0x5219b485,
+               .actim_ctrlb = 0x00012210,
+               .rfr_ctrl    = 0x0003de01,
+               .mr          = 0x00000032,
+       },
+       [2] = {
+               .rate        = 82970588,
+               .actim_ctrla = 0x31512283,
+               .actim_ctrlb = 0x0001220a,
+               .rfr_ctrl    = 0x00025501,
+               .mr          = 0x00000022,
+       },
+       [3] = {
+               .rate        = 66666666,
+               .actim_ctrla = 0x290d2243,
+               .actim_ctrlb = 0x00012208,
+               .rfr_ctrl    = 0x0001d601,
+               .mr          = 0x00000022,
+       },
+       [4] = {
+               .rate        = 0
+       },
+};
+
+#endif
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
new file mode 100644 (file)
index 0000000..2a30060
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SMS/SDRC (SDRAM controller) common code for OMAP2/3
+ *
+ * Copyright (C) 2005, 2008 Texas Instruments Inc.
+ * Copyright (C) 2005, 2008 Nokia Corporation
+ *
+ * Tony Lindgren <tony@atomide.com>
+ * Paul Walmsley
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/common.h>
+#include <mach/clock.h>
+#include <mach/sram.h>
+
+#include "prm.h"
+
+#include <mach/sdrc.h>
+#include "sdrc.h"
+
+static struct omap_sdrc_params *sdrc_init_params;
+
+void __iomem *omap2_sdrc_base;
+void __iomem *omap2_sms_base;
+
+
+/**
+ * omap2_sdrc_get_params - return SDRC register values for a given clock rate
+ * @r: SDRC clock rate (in Hz)
+ *
+ * Return pre-calculated values for the SDRC_ACTIM_CTRLA,
+ * SDRC_ACTIM_CTRLB, SDRC_RFR_CTRL, and SDRC_MR registers, for a given
+ * SDRC clock rate 'r'.  These parameters control various timing
+ * delays in the SDRAM controller that are expressed in terms of the
+ * number of SDRC clock cycles to wait; hence the clock rate
+ * dependency. Note that sdrc_init_params must be sorted rate
+ * descending.  Also assumes that both chip-selects use the same
+ * timing parameters.  Returns a struct omap_sdrc_params * upon
+ * success, or NULL upon failure.
+ */
+struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
+{
+       struct omap_sdrc_params *sp;
+
+       sp = sdrc_init_params;
+
+       while (sp->rate != r)
+               sp++;
+
+       if (!sp->rate)
+               return NULL;
+
+       return sp;
+}
+
+
+void __init omap2_set_globals_sdrc(struct omap_globals *omap2_globals)
+{
+       omap2_sdrc_base = omap2_globals->sdrc;
+       omap2_sms_base = omap2_globals->sms;
+}
+
+/* turn on smart idle modes for SDRAM scheduler and controller */
+void __init omap2_sdrc_init(struct omap_sdrc_params *sp)
+{
+       u32 l;
+
+       l = sms_read_reg(SMS_SYSCONFIG);
+       l &= ~(0x3 << 3);
+       l |= (0x2 << 3);
+       sms_write_reg(l, SMS_SYSCONFIG);
+
+       l = sdrc_read_reg(SDRC_SYSCONFIG);
+       l &= ~(0x3 << 3);
+       l |= (0x2 << 3);
+       sdrc_write_reg(l, SDRC_SYSCONFIG);
+
+       sdrc_init_params = sp;
+}
similarity index 71%
rename from arch/arm/mach-omap2/memory.c
rename to arch/arm/mach-omap2/sdrc2xxx.c
index 6b49cc9cbdcbcb31a03e674524cd27eb26e4139e..0723e59b587f95eddb4aebeceb7925504ae4e18e 100644 (file)
@@ -1,13 +1,14 @@
 /*
  * linux/arch/arm/mach-omap2/memory.c
  *
- * Memory timing related functions for OMAP24XX
+ * Memory timing related functions for OMAP2xxx
  *
- * Copyright (C) 2005 Texas Instruments Inc.
- * Richard Woodruff <r-woodruff2@ti.com>
+ * Copyright (C) 2005, 2008 Texas Instruments Inc.
+ * Copyright (C) 2005, 2008 Nokia Corporation
  *
- * Copyright (C) 2005 Nokia Corporation
  * Tony Lindgren <tony@atomide.com>
+ * Paul Walmsley
+ * Richard Woodruff <r-woodruff2@ti.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,8 +22,7 @@
 #include <linux/errno.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/common.h>
 #include <mach/clock.h>
 
 #include "prm.h"
 
-#include "memory.h"
+#include <mach/sdrc.h>
 #include "sdrc.h"
 
-void __iomem *omap2_sdrc_base;
-void __iomem *omap2_sms_base;
+/* Memory timing, DLL mode flags */
+#define M_DDR          1
+#define M_LOCK_CTRL    (1 << 2)
+#define M_UNLOCK       0
+#define M_LOCK         1
+
 
 static struct memory_timings mem_timings;
 static u32 curr_perf_level = CORE_CLK_SRC_DPLL_X2;
 
-u32 omap2_memory_get_slow_dll_ctrl(void)
+static u32 omap2xxx_sdrc_get_slow_dll_ctrl(void)
 {
        return mem_timings.slow_dll_ctrl;
 }
 
-u32 omap2_memory_get_fast_dll_ctrl(void)
+static u32 omap2xxx_sdrc_get_fast_dll_ctrl(void)
 {
        return mem_timings.fast_dll_ctrl;
 }
 
-u32 omap2_memory_get_type(void)
+static u32 omap2xxx_sdrc_get_type(void)
 {
        return mem_timings.m_type;
 }
@@ -58,7 +62,7 @@ u32 omap2_memory_get_type(void)
  * Check the DLL lock state, and return tue if running in unlock mode.
  * This is needed to compensate for the shifted DLL value in unlock mode.
  */
-u32 omap2_dll_force_needed(void)
+u32 omap2xxx_sdrc_dll_is_unlocked(void)
 {
        /* dlla and dllb are a set */
        u32 dll_state = sdrc_read_reg(SDRC_DLLA_CTRL);
@@ -73,8 +77,10 @@ u32 omap2_dll_force_needed(void)
  * 'level' is the value to store to CM_CLKSEL2_PLL.CORE_CLK_SRC.
  * Practical values are CORE_CLK_SRC_DPLL (for CORE_CLK = DPLL_CLK) or
  * CORE_CLK_SRC_DPLL_X2 (for CORE_CLK = * DPLL_CLK * 2)
+ *
+ * Used by the clock framework during CORE DPLL changes
  */
-u32 omap2_reprogram_sdrc(u32 level, u32 force)
+u32 omap2xxx_sdrc_reprogram(u32 level, u32 force)
 {
        u32 dll_ctrl, m_type;
        u32 prev = curr_perf_level;
@@ -83,18 +89,18 @@ u32 omap2_reprogram_sdrc(u32 level, u32 force)
        if ((curr_perf_level == level) && !force)
                return prev;
 
-       if (level == CORE_CLK_SRC_DPLL) {
-               dll_ctrl = omap2_memory_get_slow_dll_ctrl();
-       } else if (level == CORE_CLK_SRC_DPLL_X2) {
-               dll_ctrl = omap2_memory_get_fast_dll_ctrl();
-       } else {
+       if (level == CORE_CLK_SRC_DPLL)
+               dll_ctrl = omap2xxx_sdrc_get_slow_dll_ctrl();
+       else if (level == CORE_CLK_SRC_DPLL_X2)
+               dll_ctrl = omap2xxx_sdrc_get_fast_dll_ctrl();
+       else
                return prev;
-       }
 
-       m_type = omap2_memory_get_type();
+       m_type = omap2xxx_sdrc_get_type();
 
        local_irq_save(flags);
-       __raw_writel(0xffff, OMAP24XX_PRCM_VOLTSETUP);
+       prm_write_mod_reg(0xffff, OMAP24XX_GR_MOD,
+                         OMAP24XX_PRCM_VOLTSETUP_OFFSET);
        omap2_sram_reprogram_sdrc(level, dll_ctrl, m_type);
        curr_perf_level = level;
        local_irq_restore(flags);
@@ -102,12 +108,14 @@ u32 omap2_reprogram_sdrc(u32 level, u32 force)
        return prev;
 }
 
-void omap2_init_memory_params(u32 force_lock_to_unlock_mode)
+/* Used by the clock framework during CORE DPLL changes */
+void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode)
 {
        unsigned long dll_cnt;
        u32 fast_dll = 0;
 
-       mem_timings.m_type = !((sdrc_read_reg(SDRC_MR_0) & 0x3) == 0x1); /* DDR = 1, SDR = 0 */
+       /* DDR = 1, SDR = 0 */
+       mem_timings.m_type = !((sdrc_read_reg(SDRC_MR_0) & 0x3) == 0x1);
 
        /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others.
         * In the case of 2422, its ok to use CS1 instead of CS0.
@@ -154,25 +162,3 @@ 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));
 }
-
-void __init omap2_set_globals_memory(struct omap_globals *omap2_globals)
-{
-       omap2_sdrc_base = omap2_globals->sdrc;
-       omap2_sms_base = omap2_globals->sms;
-}
-
-/* turn on smart idle modes for SDRAM scheduler and controller */
-void __init omap2_init_memory(void)
-{
-       u32 l;
-
-       l = sms_read_reg(SMS_SYSCONFIG);
-       l &= ~(0x3 << 3);
-       l |= (0x2 << 3);
-       sms_write_reg(l, SMS_SYSCONFIG);
-
-       l = sdrc_read_reg(SDRC_SYSCONFIG);
-       l &= ~(0x3 << 3);
-       l |= (0x2 << 3);
-       sdrc_write_reg(l, SDRC_SYSCONFIG);
-}
index adc8a26a8fb01757ee6f18ced5104ac9db1edaa8..dbbef9015a0cc7dade6203beb05024bd674f952b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * OMAP2 serial support.
  *
- * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2005-2008 Nokia Corporation
  * Author: Paul Mundt <paul.mundt@nokia.com>
  *
  * Based off of arch/arm/mach-omap/omap1/serial.c
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 #include <mach/common.h>
 #include <mach/board.h>
 
-static struct clk * uart1_ick = NULL;
-static struct clk * uart1_fck = NULL;
-static struct clk * uart2_ick = NULL;
-static struct clk * uart2_fck = NULL;
-static struct clk * uart3_ick = NULL;
-static struct clk * uart3_fck = NULL;
+static struct clk *uart_ick[OMAP_MAX_NR_PORTS];
+static struct clk *uart_fck[OMAP_MAX_NR_PORTS];
 
 static struct plat_serial8250_port serial_platform_data[] = {
        {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART1_BASE),
-               .mapbase        = (unsigned long)OMAP_UART1_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART1_BASE),
+               .mapbase        = OMAP_UART1_BASE,
                .irq            = 72,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART2_BASE),
-               .mapbase        = (unsigned long)OMAP_UART2_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART2_BASE),
+               .mapbase        = OMAP_UART2_BASE,
                .irq            = 73,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
-               .membase        = (char *)IO_ADDRESS(OMAP_UART3_BASE),
-               .mapbase        = (unsigned long)OMAP_UART3_BASE,
+               .membase        = IO_ADDRESS(OMAP_UART3_BASE),
+               .mapbase        = OMAP_UART3_BASE,
                .irq            = 74,
                .flags          = UPF_BOOT_AUTOCONF,
                .iotype         = UPIO_MEM,
                .regshift       = 2,
-               .uartclk        = OMAP16XX_BASE_BAUD * 16,
+               .uartclk        = OMAP24XX_BASE_BAUD * 16,
        }, {
                .flags          = 0
        }
@@ -71,7 +67,7 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
                                    int value)
 {
        offset <<= p->regshift;
-       __raw_writeb(value, (unsigned long)(p->membase + offset));
+       __raw_writeb(value, p->membase + offset);
 }
 
 /*
@@ -87,10 +83,27 @@ static inline void __init omap_serial_reset(struct plat_serial8250_port *p)
        serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
 }
 
-void __init omap_serial_init()
+void omap_serial_enable_clocks(int enable)
+{
+       int i;
+       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+               if (uart_ick[i] && uart_fck[i]) {
+                       if (enable) {
+                               clk_enable(uart_ick[i]);
+                               clk_enable(uart_fck[i]);
+                       } else {
+                               clk_disable(uart_ick[i]);
+                               clk_disable(uart_fck[i]);
+                       }
+               }
+       }
+}
+
+void __init omap_serial_init(void)
 {
        int i;
        const struct omap_uart_config *info;
+       char name[16];
 
        /*
         * Make sure the serial ports are muxed on at this point.
@@ -98,8 +111,7 @@ void __init omap_serial_init()
         * if not needed.
         */
 
-       info = omap_get_config(OMAP_TAG_UART,
-                              struct omap_uart_config);
+       info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
 
        if (info == NULL)
                return;
@@ -108,58 +120,26 @@ void __init omap_serial_init()
                struct plat_serial8250_port *p = serial_platform_data + i;
 
                if (!(info->enabled_uarts & (1 << i))) {
-                       p->membase = 0;
+                       p->membase = NULL;
                        p->mapbase = 0;
                        continue;
                }
 
-               switch (i) {
-               case 0:
-                       uart1_ick = clk_get(NULL, "uart1_ick");
-                       if (IS_ERR(uart1_ick))
-                               printk("Could not get uart1_ick\n");
-                       else {
-                               clk_enable(uart1_ick);
-                       }
-
-                       uart1_fck = clk_get(NULL, "uart1_fck");
-                       if (IS_ERR(uart1_fck))
-                               printk("Could not get uart1_fck\n");
-                       else {
-                               clk_enable(uart1_fck);
-                       }
-                       break;
-               case 1:
-                       uart2_ick = clk_get(NULL, "uart2_ick");
-                       if (IS_ERR(uart2_ick))
-                               printk("Could not get uart2_ick\n");
-                       else {
-                               clk_enable(uart2_ick);
-                       }
-
-                       uart2_fck = clk_get(NULL, "uart2_fck");
-                       if (IS_ERR(uart2_fck))
-                               printk("Could not get uart2_fck\n");
-                       else {
-                               clk_enable(uart2_fck);
-                       }
-                       break;
-               case 2:
-                       uart3_ick = clk_get(NULL, "uart3_ick");
-                       if (IS_ERR(uart3_ick))
-                               printk("Could not get uart3_ick\n");
-                       else {
-                               clk_enable(uart3_ick);
-                       }
-
-                       uart3_fck = clk_get(NULL, "uart3_fck");
-                       if (IS_ERR(uart3_fck))
-                               printk("Could not get uart3_fck\n");
-                       else {
-                               clk_enable(uart3_fck);
-                       }
-                       break;
-               }
+               sprintf(name, "uart%d_ick", i+1);
+               uart_ick[i] = clk_get(NULL, name);
+               if (IS_ERR(uart_ick[i])) {
+                       printk(KERN_ERR "Could not get uart%d_ick\n", i+1);
+                       uart_ick[i] = NULL;
+               } else
+                       clk_enable(uart_ick[i]);
+
+               sprintf(name, "uart%d_fck", i+1);
+               uart_fck[i] = clk_get(NULL, name);
+               if (IS_ERR(uart_fck[i])) {
+                       printk(KERN_ERR "Could not get uart%d_fck\n", i+1);
+                       uart_fck[i] = NULL;
+               } else
+                       clk_enable(uart_fck[i]);
 
                omap_serial_reset(p);
        }
similarity index 85%
rename from arch/arm/mach-omap2/sleep.S
rename to arch/arm/mach-omap2/sleep24xx.S
index 87a706fd5f8214f13fb1c9894f9f344161b6a3ed..43336b93b21c0398494c19a925c88f24a37c709a 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
@@ -26,6 +30,8 @@
 #include <mach/io.h>
 #include <mach/pm.h>
 
+#include <mach/omap24xx.h>
+
 #include "sdrc.h"
 
 /* First address of reserved address space?  apparently valid for OMAP2 & 3 */
@@ -52,15 +58,14 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
        .word   . - omap24xx_idle_loop_suspend
 
 /*
- * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing
+ * omap24xx_cpu_suspend() - Forces OMAP into deep sleep state by completing
  * SDRC shutdown then ARM shutdown.  Upon wake MPU is back on so just restore
  * SDRC.
  *
  * Input:
  * R0 :        DLL ctrl value pre-Sleep
- * R1 : Processor+Revision
- *     2420: 0x21 = 242xES1, 0x26 = 242xES2.2
- *     2430: 0x31 = 2430ES1, 0x32 = 2430ES2
+ * R1 : SDRC_DLLA_CTRL
+ * R2 : SDRC_POWER
  *
  * 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
@@ -80,15 +85,14 @@ ENTRY(omap24xx_idle_loop_suspend_sz)
  */
 ENTRY(omap24xx_cpu_suspend)
        stmfd   sp!, {r0 - r12, lr}     @ save registers on stack
-       mov     r3, #0x0                @ clear for mrc call
+       mov     r3, #0x0                @ clear for mcr call
        mcr     p15, 0, r3, c7, c10, 4  @ memory barrier, hope SDR/DDR finished
        nop
        nop
-       ldr     r3, A_SDRC_POWER        @ addr of sdrc power
-       ldr     r4, [r3]                @ value of sdrc power
+       ldr     r4, [r2]                @ read SDRC_POWER
        orr     r4, r4, #0x40           @ enable self refresh on idle req
        mov     r5, #0x2000             @ set delay (DPLL relock + DLL relock)
-       str     r4, [r3]                @ make it so
+       str     r4, [r2]                @ make it so
        mov     r2, #0
        nop
        mcr     p15, 0, r2, c7, c0, 4   @ wait for interrupt
@@ -97,14 +101,13 @@ loop:
        subs    r5, r5, #0x1            @ awake, wait just a bit
        bne     loop
 
-       /* The DPLL has on before we take the DDR out of self refresh */
+       /* The DPLL has to be on before we take the DDR out of self refresh */
        bic     r4, r4, #0x40           @ now clear self refresh bit.
-       str     r4, [r3]                @ put vlaue back.
+       str     r4, [r2]                @ write to SDRC_POWER
        ldr     r4, A_SDRC0             @ make a clock happen
-       ldr     r4, [r4]
+       ldr     r4, [r4]                @ read A_SDRC0
        nop                             @ start auto refresh only after clk ok
        movs    r0, r0                  @ see if DDR or SDR
-       ldrne   r1, A_SDRC_DLLA_CTRL_S  @ get addr of DLL ctrl
        strne   r0, [r1]                @ rewrite DLLA to force DLL reload
        addne   r1, r1, #0x8            @ move to DLLB
        strne   r0, [r1]                @ rewrite DLLB to force DLL reload
@@ -116,13 +119,8 @@ loop2:
        /* resume*/
        ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
 
-A_SDRC_POWER:
-       .word OMAP242X_SDRC_REGADDR(SDRC_POWER)
 A_SDRC0:
        .word A_SDRC0_V
-A_SDRC_DLLA_CTRL_S:
-       .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL)
 
 ENTRY(omap24xx_cpu_suspend_sz)
        .word   . - omap24xx_cpu_suspend
-
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644 (file)
index 0000000..125b75a
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * linux/arch/arm/mach-omap2/sleep.S
+ *
+ * (C) Copyright 2007
+ * Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/io.h>
+#include <mach/pm.h>
+#include <mach/control.h>
+
+#include "prm.h"
+#include "sdrc.h"
+
+#define PM_PREPWSTST_CORE_V    OMAP34XX_PRM_REGADDR(CORE_MOD, \
+                               OMAP3430_PM_PREPWSTST)
+#define PM_PREPWSTST_MPU_V     OMAP34XX_PRM_REGADDR(MPU_MOD, \
+                               OMAP3430_PM_PREPWSTST)
+#define PM_PWSTCTRL_MPU_P      OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
+#define SCRATCHPAD_MEM_OFFS    0x310 /* Move this as correct place is
+                                      * available */
+#define SCRATCHPAD_BASE_P      OMAP343X_CTRL_REGADDR(\
+                               OMAP343X_CONTROL_MEM_WKUP +\
+                               SCRATCHPAD_MEM_OFFS)
+#define SDRC_POWER_V           OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+
+       .text
+/* Function call to get the restore pointer for resume from OFF */
+ENTRY(get_restore_pointer)
+        stmfd   sp!, {lr}     @ save registers on stack
+       adr     r0, restore
+        ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(get_restore_pointer_sz)
+        .word   . - get_restore_pointer_sz
+/*
+ * Forces OMAP into idle state
+ *
+ * omap34xx_suspend() - This bit of code just executes the WFI
+ * for normal idles.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *      wakes up it continues execution at the point it went to sleep.
+ */
+ENTRY(omap34xx_cpu_suspend)
+       stmfd   sp!, {r0-r12, lr}               @ save registers on stack
+loop:
+       /*b     loop*/  @Enable to debug by stepping through code
+       /* r0 contains restore pointer in sdram */
+       /* r1 contains information about saving context */
+       ldr     r4, sdrc_power          @ read the SDRC_POWER register
+       ldr     r5, [r4]                @ read the contents of SDRC_POWER
+       orr     r5, r5, #0x40           @ enable self refresh on idle req
+       str     r5, [r4]                @ write back to SDRC_POWER register
+
+       cmp     r1, #0x0
+       /* If context save is required, do that and execute wfi */
+       bne     save_context_wfi
+       /* Data memory barrier and Data sync barrier */
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c10, 4
+       mcr     p15, 0, r1, c7, c10, 5
+
+       wfi                             @ wait for interrupt
+
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bl i_dll_wait
+
+       ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
+restore:
+       /* b restore*/  @ Enable to debug restore code
+        /* Check what was the reason for mpu reset and store the reason in r9*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost - In this case, we wont be here */
+        /* 3 - Both L1 and L2 lost */
+       ldr     r1, pm_pwstctrl_mpu
+       ldr     r2, [r1]
+       and     r2, r2, #0x3
+       cmp     r2, #0x0        @ Check if target power state was OFF or RET
+        moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
+       movne   r9, #0x1        @ Only L1 and L2 lost => avoid L2 invalidation
+       bne     logic_l1_restore
+       /* Execute smi to invalidate L2 cache */
+       mov r12, #0x1                         @ set up to invalide L2
+smi:    .word 0xE1600070                @ Call SMI monitor (smieq)
+logic_l1_restore:
+       mov     r1, #0
+       /* Invalidate all instruction caches to PoU
+        * and flush branch target cache */
+       mcr     p15, 0, r1, c7, c5, 0
+
+       ldr     r4, scratchpad_base
+       ldr     r3, [r4,#0xBC]
+       ldmia   r3!, {r4-r6}
+       mov     sp, r4
+       msr     spsr_cxsf, r5
+       mov     lr, r6
+
+       ldmia   r3!, {r4-r9}
+       /* Coprocessor access Control Register */
+       mcr p15, 0, r4, c1, c0, 2
+
+       /* TTBR0 */
+       MCR p15, 0, r5, c2, c0, 0
+       /* TTBR1 */
+       MCR p15, 0, r6, c2, c0, 1
+       /* Translation table base control register */
+       MCR p15, 0, r7, c2, c0, 2
+       /*domain access Control Register */
+       MCR p15, 0, r8, c3, c0, 0
+       /* data fault status Register */
+       MCR p15, 0, r9, c5, c0, 0
+
+       ldmia  r3!,{r4-r8}
+       /* instruction fault status Register */
+       MCR p15, 0, r4, c5, c0, 1
+       /*Data Auxiliary Fault Status Register */
+       MCR p15, 0, r5, c5, c1, 0
+       /*Instruction Auxiliary Fault Status Register*/
+       MCR p15, 0, r6, c5, c1, 1
+       /*Data Fault Address Register */
+       MCR p15, 0, r7, c6, c0, 0
+       /*Instruction Fault Address Register*/
+       MCR p15, 0, r8, c6, c0, 2
+       ldmia  r3!,{r4-r7}
+
+       /* user r/w thread and process ID */
+       MCR p15, 0, r4, c13, c0, 2
+       /* user ro thread and process ID */
+       MCR p15, 0, r5, c13, c0, 3
+       /*Privileged only thread and process ID */
+       MCR p15, 0, r6, c13, c0, 4
+       /* cache size selection */
+       MCR p15, 2, r7, c0, c0, 0
+       ldmia  r3!,{r4-r8}
+       /* Data TLB lockdown registers */
+       MCR p15, 0, r4, c10, c0, 0
+       /* Instruction TLB lockdown registers */
+       MCR p15, 0, r5, c10, c0, 1
+       /* Secure or Nonsecure Vector Base Address */
+       MCR p15, 0, r6, c12, c0, 0
+       /* FCSE PID */
+       MCR p15, 0, r7, c13, c0, 0
+       /* Context PID */
+       MCR p15, 0, r8, c13, c0, 1
+
+       ldmia  r3!,{r4-r5}
+       /* primary memory remap register */
+       MCR p15, 0, r4, c10, c2, 0
+       /*normal memory remap register */
+       MCR p15, 0, r5, c10, c2, 1
+
+       /* Restore registers for other modes from SDRAM */
+       /* Save current mode */
+       mrs     r7, cpsr
+
+       /* FIQ mode */
+       bic     r0, r7, #0x1F
+       orr     r0, r0, #0x11
+       msr     cpsr, r0
+       ldmia   r3!, {r8-r12}
+       /* load the SP and LR from SDRAM */
+       ldmia  r3!,{r4-r6}
+       mov    sp, r4   /*update the SP */
+       mov    lr, r5   /*update the LR */
+       msr    spsr, r6 /*update the SPSR*/
+
+       /* IRQ mode */
+       bic    r0, r7, #0x1F
+       orr    r0, r0, #0x12
+       msr    cpsr, r0 /*go into IRQ mode*/
+       ldmia  r3!,{r4-r6}      /*load the SP and LR from SDRAM*/
+       mov    sp, r4   /*update the SP */
+       mov    lr, r5   /*update the LR */
+       msr    spsr, r6 /*update the SPSR */
+
+       /* ABORT mode */
+       bic    r0, r7, #0x1F
+       orr    r0, r0, #0x17
+       msr    cpsr, r0 /* go into ABORT mode */
+       ldmia  r3!,{r4-r6}      /*load the SP and LR from SDRAM */
+       mov    sp, r4           /*update the SP */
+       mov    lr, r5           /*update the LR */
+       msr    spsr, r6         /*update the SPSR */
+
+       /* UNDEEF mode */
+       bic    r0, r7, #0x1F
+       orr    r0, r0, #0x1B
+       msr    cpsr, r0         /*go into UNDEF mode */
+       ldmia  r3!,{r4-r6}      /*load the SP and LR from SDRAM */
+       mov    sp, r4           /*update the SP*/
+       mov    lr, r5           /*update the LR*/
+       msr    spsr, r6         /*update the SPSR*/
+
+       /* SYSTEM (USER) mode */
+       bic    r0, r7, #0x1F
+       orr    r0, r0, #0x1F
+       msr    cpsr, r0         /*go into USR mode */
+       ldmia  r3!,{r4-r6}      /*load the SP and LR from SDRAM*/
+       mov    sp, r4           /*update the SP */
+       mov    lr, r5           /*update the LR */
+       msr    spsr, r6         /*update the SPSR */
+       msr    cpsr, r7         /*back to original mode*/
+
+       /* Restore cpsr */
+       ldmia   r3!,{r4}        /*load CPSR from SDRAM*/
+       msr     cpsr, r4        /*store cpsr */
+
+       /* Enabling MMU here */
+       mrc     p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
+       /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
+       and     r7, #0x7
+       cmp     r7, #0x0
+       beq     usettbr0
+ttbr_error:
+       /* More work needs to be done to support N[0:2] value other than 0
+       * So looping here so that the error can be detected
+       */
+       b       ttbr_error
+usettbr0:
+       mrc     p15, 0, r2, c2, c0, 0
+       ldr     r5, ttbrbit_mask
+       and     r2, r5
+       mov     r4, pc
+       ldr     r5, table_index_mask
+       and     r4, r5 /* r4 = 31 to 20 bits of pc */
+       /* Extract the value to be written to table entry */
+       ldr     r1, table_entry
+       add     r1, r1, r4 /* r1 has value to be written to table entry*/
+       /* Getting the address of table entry to modify */
+       lsr     r4, #18
+       add     r2, r4 /* r2 has the location which needs to be modified */
+       /* Storing previous entry of location being modified */
+       ldr     r5, scratchpad_base
+       ldr     r4, [r2]
+       str     r4, [r5, #0xC0]
+       /* Modify the table entry */
+       str     r1, [r2]
+       /* Storing address of entry being modified
+        * - will be restored after enabling MMU */
+       ldr     r5, scratchpad_base
+       str     r2, [r5, #0xC4]
+
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 4   @ Flush prefetch buffer
+       mcr     p15, 0, r0, c7, c5, 6   @ Invalidate branch predictor array
+       mcr     p15, 0, r0, c8, c5, 0   @ Invalidate instruction TLB
+       mcr     p15, 0, r0, c8, c6, 0   @ Invalidate data TLB
+       /* Restore control register  but dont enable caches here*/
+       /* Caches will be enabled after restoring MMU table entry */
+       ldmia   r3!, {r4}
+       /* Store previous value of control register in scratchpad */
+       str     r4, [r5, #0xC8]
+       ldr     r2, cache_pred_disable_mask
+       and     r4, r2
+       mcr     p15, 0, r4, c1, c0, 0
+
+       ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
+save_context_wfi:
+       /*b     save_context_wfi*/      @ enable to debug save code
+       mov     r8, r0 /* Store SDRAM address in r8 */
+        /* Check what that target sleep state is:stored in r1*/
+        /* 1 - Only L1 and logic lost */
+        /* 2 - Only L2 lost */
+        /* 3 - Both L1 and L2 lost */
+       cmp     r1, #0x2 /* Only L2 lost */
+       beq     clean_l2
+       cmp     r1, #0x1 /* L2 retained */
+       /* r9 stores whether to clean L2 or not*/
+       moveq   r9, #0x0 /* Dont Clean L2 */
+       movne   r9, #0x1 /* Clean L2 */
+l1_logic_lost:
+       /* Store sp and spsr to SDRAM */
+       mov     r4, sp
+       mrs     r5, spsr
+       mov     r6, lr
+       stmia   r8!, {r4-r6}
+       /* Save all ARM registers */
+       /* Coprocessor access control register */
+       mrc     p15, 0, r6, c1, c0, 2
+       stmia   r8!, {r6}
+       /* TTBR0, TTBR1 and Translation table base control */
+       mrc     p15, 0, r4, c2, c0, 0
+       mrc     p15, 0, r5, c2, c0, 1
+       mrc     p15, 0, r6, c2, c0, 2
+       stmia   r8!, {r4-r6}
+       /* Domain access control register, data fault status register,
+       and instruction fault status register */
+       mrc     p15, 0, r4, c3, c0, 0
+       mrc     p15, 0, r5, c5, c0, 0
+       mrc     p15, 0, r6, c5, c0, 1
+       stmia   r8!, {r4-r6}
+       /* Data aux fault status register, instruction aux fault status,
+       datat fault address register and instruction fault address register*/
+       mrc     p15, 0, r4, c5, c1, 0
+       mrc     p15, 0, r5, c5, c1, 1
+       mrc     p15, 0, r6, c6, c0, 0
+       mrc     p15, 0, r7, c6, c0, 2
+       stmia   r8!, {r4-r7}
+       /* user r/w thread and process ID, user r/o thread and process ID,
+       priv only thread and process ID, cache size selection */
+       mrc     p15, 0, r4, c13, c0, 2
+       mrc     p15, 0, r5, c13, c0, 3
+       mrc     p15, 0, r6, c13, c0, 4
+       mrc     p15, 2, r7, c0, c0, 0
+       stmia   r8!, {r4-r7}
+       /* Data TLB lockdown, instruction TLB lockdown registers */
+       mrc     p15, 0, r5, c10, c0, 0
+       mrc     p15, 0, r6, c10, c0, 1
+       stmia   r8!, {r5-r6}
+       /* Secure or non secure vector base address, FCSE PID, Context PID*/
+       mrc     p15, 0, r4, c12, c0, 0
+       mrc     p15, 0, r5, c13, c0, 0
+       mrc     p15, 0, r6, c13, c0, 1
+       stmia   r8!, {r4-r6}
+       /* Primary remap, normal remap registers */
+       mrc     p15, 0, r4, c10, c2, 0
+       mrc     p15, 0, r5, c10, c2, 1
+       stmia   r8!,{r4-r5}
+       /* Store SP, LR, SPSR registers for SUP, FIQ, IRQ, ABORT and USER
+       modes into SDRAM */
+
+       /* move SDRAM address to r7 as r8 is banked in FIQ*/
+       mov     r7, r8
+
+       /* Save current mode */
+       mrs     r2, cpsr
+       /* FIQ mode */
+       bic     r0, r2, #0x1F
+       orr     r0, r0, #0x11
+       msr     cpsr, r0 /* go to FIQ mode */
+       stmia   r7!, {r8-r12}
+       mov     r4, r13 /* move SP into r4*/
+       mov     r5, r14
+       mrs     r6, spsr
+       stmia   r7!, {r4-r6}
+
+       /* IRQ mode */
+       bic     r0, r2, #0x1F
+       orr     r0, r0, #0x12
+       msr     cpsr, r0
+       mov     r4, r13
+       mov     r5, r14
+       mrs     r6, spsr
+       stmia   r7!, {r4-r6}
+
+       /* Abort mode */
+       bic     r0, r2, #0x1F
+       orr     r0, r0, #0x17
+       msr     cpsr, r0
+       mov     r4, r13
+       mov     r5, r14
+       mrs     r6, spsr
+       stmia   r7!, {r4-r6}
+
+       /* UNDEF mode */
+       bic     r0, r2, #0x1F
+       orr     r0, r0, #0x1B
+       msr     cpsr, r0
+       mov     r4, r13
+       mov     r5, r14
+       mrs     r6, spsr
+       stmia   r7!, {r4-r6}
+
+       /* System (USER mode) */
+       bic     r0, r2, #0x1F
+       orr     r0, r0, #0x1F
+       msr     cpsr, r0
+       mov     r4, r13
+       mov     r5, r14
+       mrs     r6, spsr
+       stmia   r7!, {r4-r6}
+
+       /* Back to original mode */
+       msr     cpsr, r2
+
+       /* Store current cpsr*/
+       stmia   r7!, {r2}
+
+       mrc     p15, 0, r4, c1, c0, 0
+       /* save control register */
+       stmia   r7!, {r4}
+clean_caches:
+       /* Clean Data or unified cache to POU*/
+       /* How to invalidate only L1 cache???? - #FIX_ME# */
+       /* mcr  p15, 0, r11, c7, c11, 1 */
+       cmp     r9, #1 /* Check whether L2 inval is required or not*/
+       bne     skip_l2_inval
+clean_l2:
+       /* read clidr */
+       mrc     p15, 1, r0, c0, c0, 1
+       /* extract loc from clidr */
+       ands    r3, r0, #0x7000000
+       /* left align loc bit field */
+       mov     r3, r3, lsr #23
+       /* if loc is 0, then no need to clean */
+       beq     finished
+       /* start clean at cache level 0 */
+       mov     r10, #0
+loop1:
+       /* work out 3x current cache level */
+       add     r2, r10, r10, lsr #1
+       /* extract cache type bits from clidr*/
+       mov     r1, r0, lsr r2
+       /* mask of the bits for current cache only */
+       and     r1, r1, #7
+       /* see what cache we have at this level */
+       cmp     r1, #2
+       /* skip if no cache, or just i-cache */
+       blt     skip
+       /* select current cache level in cssr */
+       mcr     p15, 2, r10, c0, c0, 0
+       /* isb to sych the new cssr&csidr */
+       isb
+       /* read the new csidr */
+       mrc     p15, 1, r1, c0, c0, 0
+       /* extract the length of the cache lines */
+       and     r2, r1, #7
+       /* add 4 (line length offset) */
+       add     r2, r2, #4
+       ldr     r4, assoc_mask
+       /* find maximum number on the way size */
+       ands    r4, r4, r1, lsr #3
+       /* find bit position of way size increment */
+       clz     r5, r4
+       ldr     r7, numset_mask
+       /* extract max number of the index size*/
+       ands    r7, r7, r1, lsr #13
+loop2:
+       mov     r9, r4
+       /* create working copy of max way size*/
+loop3:
+       /* factor way and cache number into r11 */
+       orr     r11, r10, r9, lsl r5
+       /* factor index number into r11 */
+       orr     r11, r11, r7, lsl r2
+       /*clean & invalidate by set/way */
+       mcr     p15, 0, r11, c7, c10, 2
+       /* decrement the way*/
+       subs    r9, r9, #1
+       bge     loop3
+       /*decrement the index */
+       subs    r7, r7, #1
+       bge     loop2
+skip:
+       add     r10, r10, #2
+       /* increment cache number */
+       cmp     r3, r10
+       bgt     loop1
+finished:
+       /*swith back to cache level 0 */
+       mov     r10, #0
+       /* select current cache level in cssr */
+       mcr     p15, 2, r10, c0, c0, 0
+       isb
+skip_l2_inval:
+       /* Data memory barrier and Data sync barrier */
+       mov     r1, #0
+       mcr     p15, 0, r1, c7, c10, 4
+       mcr     p15, 0, r1, c7, c10, 5
+
+       wfi                             @ wait for interrupt
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bl i_dll_wait
+       /* restore regs and return */
+       ldmfd   sp!, {r0-r12, pc}
+
+i_dll_wait:
+       ldr     r4, clk_stabilize_delay
+
+i_dll_delay:
+       subs    r4, r4, #0x1
+       bne     i_dll_delay
+       ldr     r4, sdrc_power
+       ldr     r5, [r4]
+       bic     r5, r5, #0x40
+       str     r5, [r4]
+       bx      lr
+pm_prepwstst_core:
+       .word   PM_PREPWSTST_CORE_V
+pm_prepwstst_mpu:
+       .word   PM_PREPWSTST_MPU_V
+pm_pwstctrl_mpu:
+       .word   PM_PWSTCTRL_MPU_P
+scratchpad_base:
+       .word   SCRATCHPAD_BASE_P
+sdrc_power:
+       .word SDRC_POWER_V
+context_mem:
+       .word   0x803E3E14
+clk_stabilize_delay:
+       .word 0x000001FF
+assoc_mask:
+       .word   0x3ff
+numset_mask:
+       .word   0x7fff
+ttbrbit_mask:
+       .word   0xFFFFC000
+table_index_mask:
+       .word   0xFFF00000
+table_entry:
+       .word   0x00000C02
+cache_pred_disable_mask:
+       .word   0xFFFFE7FB
+ENTRY(omap34xx_cpu_suspend_sz)
+       .word   . - omap34xx_cpu_suspend
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
new file mode 100644 (file)
index 0000000..e54c0fb
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * linux/arch/arm/mach-omap3/smartreflex.c
+ *
+ * OMAP34XX SmartReflex Voltage Control
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/io.h>
+
+#include <mach/omap34xx.h>
+#include <mach/control.h>
+#include <mach/clock.h>
+
+#include "prm.h"
+#include "smartreflex.h"
+#include "prm-regbits-34xx.h"
+
+/* XXX: These should be relocated where-ever the OPP implementation will be */
+u32 current_vdd1_opp;
+u32 current_vdd2_opp;
+
+struct omap_sr {
+       int             srid;
+       int             is_sr_reset;
+       int             is_autocomp_active;
+       struct clk      *clk;
+       u32             clk_length;
+       u32             req_opp_no;
+       u32             opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue;
+       u32             opp5_nvalue;
+       u32             senp_mod, senn_mod;
+       u32             srbase_addr;
+       u32             vpbase_addr;
+};
+
+/* Custom clocks to enable SR specific enable/disable functions. */
+struct sr_custom_clk {
+       struct clk      clk;  /* meta-clock with custom enable/disable calls */
+       struct clk      *fck; /* actual functional clock */
+       struct omap_sr  *sr;
+};
+
+#define SR_REGADDR(offs)     (__force void __iomem *)(sr->srbase_addr + offset)
+
+static inline void sr_write_reg(struct omap_sr *sr, int offset, u32 value)
+{
+       __raw_writel(value, SR_REGADDR(offset));
+}
+
+static inline void sr_modify_reg(struct omap_sr *sr, int offset, u32 mask,
+                                                               u32 value)
+{
+       u32 reg_val;
+
+       reg_val = __raw_readl(SR_REGADDR(offset));
+       reg_val &= ~mask;
+       reg_val |= value;
+
+       __raw_writel(reg_val, SR_REGADDR(offset));
+}
+
+static inline u32 sr_read_reg(struct omap_sr *sr, int offset)
+{
+       return __raw_readl(SR_REGADDR(offset));
+}
+
+/* Custom clock handling functions */
+static int sr_clk_enable(struct clk *clk)
+{
+       struct sr_custom_clk *sr_clk = container_of(clk, struct sr_custom_clk,
+                                                                       clk);
+
+       if (clk_enable(sr_clk->fck) != 0) {
+               printk(KERN_ERR "Could not enable %s\n", sr_clk->fck->name);
+               goto clk_enable_err;
+       }
+
+       /* set fclk- active , iclk- idle */
+       sr_modify_reg(sr_clk->sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
+                                               SR_CLKACTIVITY_IOFF_FON);
+
+       return 0;
+
+clk_enable_err:
+       return -1;
+}
+
+static void sr_clk_disable(struct clk *clk)
+{
+       struct sr_custom_clk *sr_clk = container_of(clk, struct sr_custom_clk,
+                                                                       clk);
+
+       /* set fclk, iclk- idle */
+       sr_modify_reg(sr_clk->sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
+                                               SR_CLKACTIVITY_IOFF_FOFF);
+
+       clk_disable(sr_clk->fck);
+       sr_clk->sr->is_sr_reset = 1;
+}
+
+static struct omap_sr sr1 = {
+       .srid                   = SR1,
+       .is_sr_reset            = 1,
+       .is_autocomp_active     = 0,
+       .clk_length             = 0,
+       .srbase_addr            = OMAP2_IO_ADDRESS(OMAP34XX_SR1_BASE),
+};
+
+static struct omap_sr sr2 = {
+       .srid                   = SR2,
+       .is_sr_reset            = 1,
+       .is_autocomp_active     = 0,
+       .clk_length             = 0,
+       .srbase_addr            = OMAP2_IO_ADDRESS(OMAP34XX_SR2_BASE),
+};
+
+static struct sr_custom_clk sr1_custom_clk = {
+       .clk = {
+                       .name           = "sr1_custom_clk",
+                       .enable         = sr_clk_enable,
+                       .disable        = sr_clk_disable,
+       },
+       .sr     = &sr1,
+};
+
+static struct sr_custom_clk sr2_custom_clk = {
+       .clk = {
+                       .name           = "sr2_custom_clk",
+                       .enable         = sr_clk_enable,
+                       .disable        = sr_clk_disable,
+       },
+       .sr     = &sr2,
+};
+
+static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen)
+{
+       u32 gn, rn, mul;
+
+       for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
+               mul = 1 << (gn + 8);
+               rn = mul / sensor;
+               if (rn < R_MAXLIMIT) {
+                       *sengain = gn;
+                       *rnsen = rn;
+               }
+       }
+}
+
+static u32 cal_test_nvalue(u32 sennval, u32 senpval)
+{
+       u32 senpgain, senngain;
+       u32 rnsenp, rnsenn;
+
+       /* Calculating the gain and reciprocal of the SenN and SenP values */
+       cal_reciprocal(senpval, &senpgain, &rnsenp);
+       cal_reciprocal(sennval, &senngain, &rnsenn);
+
+       return ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
+               (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
+               (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
+               (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
+}
+
+static void sr_clk_init(struct sr_custom_clk *sr_clk)
+{
+       if (sr_clk->sr->srid == SR1) {
+               sr_clk->fck = clk_get(NULL, "sr1_fck");
+               if (IS_ERR(sr_clk->fck))
+                       printk(KERN_ERR "Could not get sr1_fck\n");
+       } else if (sr_clk->sr->srid == SR2) {
+               sr_clk->fck = clk_get(NULL, "sr2_fck");
+               if (IS_ERR(sr_clk->fck))
+                       printk(KERN_ERR "Could not get sr2_fck\n");
+       }
+       clk_register(&sr_clk->clk);
+}
+
+static void sr_set_clk_length(struct omap_sr *sr)
+{
+       struct clk *osc_sys_ck;
+       u32 sys_clk = 0;
+
+       osc_sys_ck = clk_get(NULL, "osc_sys_ck");
+       sys_clk = clk_get_rate(osc_sys_ck);
+       clk_put(osc_sys_ck);
+
+       switch (sys_clk) {
+       case 12000000:
+               sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
+               break;
+       case 13000000:
+               sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
+               break;
+       case 19200000:
+               sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
+               break;
+       case 26000000:
+               sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
+               break;
+       case 38400000:
+               sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
+               break;
+       default :
+               printk(KERN_ERR "Invalid sysclk value: %d\n", sys_clk);
+               break;
+       }
+}
+
+static void sr_set_efuse_nvalues(struct omap_sr *sr)
+{
+       if (sr->srid == SR1) {
+               sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+                                       OMAP343X_SR1_SENNENABLE_MASK) >>
+                                       OMAP343X_SR1_SENNENABLE_SHIFT;
+
+               sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+                                       OMAP343X_SR1_SENPENABLE_MASK) >>
+                                       OMAP343X_SR1_SENPENABLE_SHIFT;
+
+               sr->opp5_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP5_VDD1);
+               sr->opp4_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP4_VDD1);
+               sr->opp3_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP3_VDD1);
+               sr->opp2_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP2_VDD1);
+               sr->opp1_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+       } else if (sr->srid == SR2) {
+               sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+                                       OMAP343X_SR2_SENNENABLE_MASK) >>
+                                       OMAP343X_SR2_SENNENABLE_SHIFT;
+
+               sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+                                       OMAP343X_SR2_SENPENABLE_MASK) >>
+                                       OMAP343X_SR2_SENPENABLE_SHIFT;
+
+               sr->opp3_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP3_VDD2);
+               sr->opp2_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP2_VDD2);
+               sr->opp1_nvalue = omap_ctrl_readl(
+                                       OMAP343X_CONTROL_FUSE_OPP1_VDD2);
+       }
+}
+
+/* Hard coded nvalues for testing purposes, may cause device to hang! */
+static void sr_set_testing_nvalues(struct omap_sr *sr)
+{
+       if (sr->srid == SR1) {
+               sr->senp_mod = 0x03;    /* SenN-M5 enabled */
+               sr->senn_mod = 0x03;
+
+               /* calculate nvalues for each opp */
+               sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330);
+               sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0);
+               sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200);
+               sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0);
+               sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100);
+       } else if (sr->srid == SR2) {
+               sr->senp_mod = 0x03;
+               sr->senn_mod = 0x03;
+
+               sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200);
+               sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0);
+               sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+       }
+
+}
+
+static void sr_set_nvalues(struct omap_sr *sr)
+{
+       if (SR_TESTING_NVALUES)
+               sr_set_testing_nvalues(sr);
+       else
+               sr_set_efuse_nvalues(sr);
+}
+
+static void sr_configure_vp(int srid)
+{
+       u32 vpconfig;
+
+       if (srid == SR1) {
+               vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN
+                                       | PRM_VP1_CONFIG_INITVOLTAGE
+                                       | PRM_VP1_CONFIG_TIMEOUTEN;
+
+               prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_CONFIG_OFFSET);
+               prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
+                                       PRM_VP1_VSTEPMIN_VSTEPMIN,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_VSTEPMIN_OFFSET);
+
+               prm_write_mod_reg(PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
+                                       PRM_VP1_VSTEPMAX_VSTEPMAX,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_VSTEPMAX_OFFSET);
+
+               prm_write_mod_reg(PRM_VP1_VLIMITTO_VDDMAX |
+                                       PRM_VP1_VLIMITTO_VDDMIN |
+                                       PRM_VP1_VLIMITTO_TIMEOUT,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_VLIMITTO_OFFSET);
+
+               /* Trigger initVDD value copy to voltage processor */
+               prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_CONFIG_OFFSET);
+               /* Clear initVDD copy trigger bit */
+               prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_CONFIG_OFFSET);
+
+       } else if (srid == SR2) {
+               vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN
+                                       | PRM_VP2_CONFIG_INITVOLTAGE
+                                       | PRM_VP2_CONFIG_TIMEOUTEN;
+
+               prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_CONFIG_OFFSET);
+               prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
+                                       PRM_VP2_VSTEPMIN_VSTEPMIN,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_VSTEPMIN_OFFSET);
+
+               prm_write_mod_reg(PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
+                                       PRM_VP2_VSTEPMAX_VSTEPMAX,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_VSTEPMAX_OFFSET);
+
+               prm_write_mod_reg(PRM_VP2_VLIMITTO_VDDMAX |
+                                       PRM_VP2_VLIMITTO_VDDMIN |
+                                       PRM_VP2_VLIMITTO_TIMEOUT,
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_VLIMITTO_OFFSET);
+
+               /* Trigger initVDD value copy to voltage processor */
+               prm_set_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_CONFIG_OFFSET);
+               /* Reset initVDD copy trigger bit */
+               prm_clear_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_CONFIG_OFFSET);
+
+       }
+}
+
+static void sr_configure(struct omap_sr *sr)
+{
+       u32 sr_config;
+       u32 senp_en , senn_en;
+
+       if (sr->clk_length == 0)
+               sr_set_clk_length(sr);
+
+       senp_en = sr->senp_mod;
+       senn_en = sr->senn_mod;
+       if (sr->srid == SR1) {
+               sr_config = SR1_SRCONFIG_ACCUMDATA |
+                       (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+                       SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
+                       SRCONFIG_MINMAXAVG_EN |
+                       (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
+                       (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
+                       SRCONFIG_DELAYCTRL;
+
+               sr_write_reg(sr, SRCONFIG, sr_config);
+               sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
+                                       SR1_AVGWEIGHT_SENNAVGWEIGHT);
+
+               sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+                       SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+                       (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
+
+       } else if (sr->srid == SR2) {
+               sr_config = SR2_SRCONFIG_ACCUMDATA |
+                       (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+                       SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
+                       SRCONFIG_MINMAXAVG_EN |
+                       (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
+                       (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
+                       SRCONFIG_DELAYCTRL;
+
+               sr_write_reg(sr, SRCONFIG, sr_config);
+               sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
+                                       SR2_AVGWEIGHT_SENNAVGWEIGHT);
+               sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+                       SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+                       (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
+
+       }
+       sr->is_sr_reset = 0;
+}
+
+static int sr_enable(struct omap_sr *sr, u32 target_opp_no)
+{
+       u32 nvalue_reciprocal;
+
+       sr->req_opp_no = target_opp_no;
+
+       if (sr->srid == SR1) {
+               switch (target_opp_no) {
+               case 5:
+                       nvalue_reciprocal = sr->opp5_nvalue;
+                       break;
+               case 4:
+                       nvalue_reciprocal = sr->opp4_nvalue;
+                       break;
+               case 3:
+                       nvalue_reciprocal = sr->opp3_nvalue;
+                       break;
+               case 2:
+                       nvalue_reciprocal = sr->opp2_nvalue;
+                       break;
+               case 1:
+                       nvalue_reciprocal = sr->opp1_nvalue;
+                       break;
+               default:
+                       nvalue_reciprocal = sr->opp3_nvalue;
+                       break;
+               }
+       } else {
+               switch (target_opp_no) {
+               case 3:
+                       nvalue_reciprocal = sr->opp3_nvalue;
+                       break;
+               case 2:
+                       nvalue_reciprocal = sr->opp2_nvalue;
+                       break;
+               case 1:
+                       nvalue_reciprocal = sr->opp1_nvalue;
+                       break;
+               default:
+                       nvalue_reciprocal = sr->opp3_nvalue;
+                       break;
+               }
+       }
+
+       if (nvalue_reciprocal == 0) {
+               printk(KERN_NOTICE "OPP%d doesn't support SmartReflex\n",
+                                                               target_opp_no);
+               return SR_FALSE;
+       }
+
+       sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
+
+       /* Enable the interrupt */
+       sr_modify_reg(sr, ERRCONFIG,
+                       (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST),
+                       (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
+       if (sr->srid == SR1) {
+               /* Enable VP1 */
+               prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+                               OMAP3_PRM_VP1_CONFIG_OFFSET);
+       } else if (sr->srid == SR2) {
+               /* Enable VP2 */
+               prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+                               OMAP3_PRM_VP2_CONFIG_OFFSET);
+       }
+
+       /* SRCONFIG - enable SR */
+       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
+       return SR_TRUE;
+}
+
+static void sr_disable(struct omap_sr *sr)
+{
+       sr->is_sr_reset = 1;
+
+       /* SRCONFIG - disable SR */
+       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
+
+       if (sr->srid == SR1) {
+               /* Disable VP1 */
+               prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP1_CONFIG_OFFSET);
+       } else if (sr->srid == SR2) {
+               /* Disable VP2 */
+               prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VP2_CONFIG_OFFSET);
+       }
+}
+
+
+void sr_start_vddautocomap(int srid, u32 target_opp_no)
+{
+       struct omap_sr *sr = NULL;
+
+       if (srid == SR1)
+               sr = &sr1;
+       else if (srid == SR2)
+               sr = &sr2;
+
+       if (sr->is_sr_reset == 1) {
+               clk_enable(sr->clk);
+               sr_configure(sr);
+       }
+
+       if (sr->is_autocomp_active == 1)
+               printk(KERN_WARNING "SR%d: VDD autocomp is already active\n",
+                                                                       srid);
+
+       sr->is_autocomp_active = 1;
+       if (!sr_enable(sr, target_opp_no)) {
+               printk(KERN_WARNING "SR%d: VDD autocomp not activated\n", srid);
+               sr->is_autocomp_active = 0;
+               if (sr->is_sr_reset == 1)
+                       clk_disable(sr->clk);
+       }
+}
+EXPORT_SYMBOL(sr_start_vddautocomap);
+
+int sr_stop_vddautocomap(int srid)
+{
+       struct omap_sr *sr = NULL;
+
+       if (srid == SR1)
+               sr = &sr1;
+       else if (srid == SR2)
+               sr = &sr2;
+
+       if (sr->is_autocomp_active == 1) {
+               sr_disable(sr);
+               clk_disable(sr->clk);
+               sr->is_autocomp_active = 0;
+               return SR_TRUE;
+       } else {
+               printk(KERN_WARNING "SR%d: VDD autocomp is not active\n",
+                                                               srid);
+               return SR_FALSE;
+       }
+
+}
+EXPORT_SYMBOL(sr_stop_vddautocomap);
+
+void enable_smartreflex(int srid)
+{
+       u32 target_opp_no = 0;
+       struct omap_sr *sr = NULL;
+
+       if (srid == SR1)
+               sr = &sr1;
+       else if (srid == SR2)
+               sr = &sr2;
+
+       if (sr->is_autocomp_active == 1) {
+               if (sr->is_sr_reset == 1) {
+                       /* Enable SR clks */
+                       clk_enable(sr->clk);
+
+                       if (srid == SR1)
+                               target_opp_no = get_opp_no(current_vdd1_opp);
+                       else if (srid == SR2)
+                               target_opp_no = get_opp_no(current_vdd2_opp);
+
+                       sr_configure(sr);
+
+                       if (!sr_enable(sr, target_opp_no))
+                               clk_disable(sr->clk);
+               }
+       }
+}
+
+void disable_smartreflex(int srid)
+{
+       struct omap_sr *sr = NULL;
+
+       if (srid == SR1)
+               sr = &sr1;
+       else if (srid == SR2)
+               sr = &sr2;
+
+       if (sr->is_autocomp_active == 1) {
+               if (sr->is_sr_reset == 0) {
+
+                       sr->is_sr_reset = 1;
+                       /* SRCONFIG - disable SR */
+                       sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
+                                                       ~SRCONFIG_SRENABLE);
+
+                       /* Disable SR clk */
+                       clk_disable(sr->clk);
+                       if (sr->srid == SR1) {
+                               /* Disable VP1 */
+                               prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE,
+                                               OMAP3430_GR_MOD,
+                                               OMAP3_PRM_VP1_CONFIG_OFFSET);
+                       } else if (sr->srid == SR2) {
+                               /* Disable VP2 */
+                               prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE,
+                                               OMAP3430_GR_MOD,
+                                               OMAP3_PRM_VP2_CONFIG_OFFSET);
+                       }
+               }
+       }
+}
+
+/* Voltage Scaling using SR VCBYPASS */
+int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
+{
+       int sr_status = 0;
+       u32 vdd, target_opp_no;
+       u32 vc_bypass_value;
+       u32 reg_addr = 0;
+       u32 loop_cnt = 0, retries_cnt = 0;
+
+       vdd = get_vdd(target_opp);
+       target_opp_no = get_opp_no(target_opp);
+
+       if (vdd == PRCM_VDD1) {
+               sr_status = sr_stop_vddautocomap(SR1);
+
+               prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+                                       (vsel << OMAP3430_VC_CMD_ON_SHIFT),
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+               reg_addr = R_VDD1_SR_CONTROL;
+
+       } else if (vdd == PRCM_VDD2) {
+               sr_status = sr_stop_vddautocomap(SR2);
+
+               prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+                                       (vsel << OMAP3430_VC_CMD_ON_SHIFT),
+                                       OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+               reg_addr = R_VDD2_SR_CONTROL;
+       }
+
+       vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) |
+                       (reg_addr << OMAP3430_REGADDR_SHIFT) |
+                       (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT);
+
+       prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD,
+                       OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+
+       vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+
+       while ((vc_bypass_value & OMAP3430_VALID) != 0x0) {
+               loop_cnt++;
+               if (retries_cnt > 10) {
+                       printk(KERN_INFO "Loop count exceeded in check SR I2C"
+                                                               "write\n");
+                       return SR_FAIL;
+               }
+               if (loop_cnt > 50) {
+                       retries_cnt++;
+                       loop_cnt = 0;
+                       udelay(10);
+               }
+               vc_bypass_value = prm_read_mod_reg(OMAP3430_GR_MOD,
+                                       OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+       }
+
+       udelay(T2_SMPS_UPDATE_DELAY);
+
+       if (sr_status) {
+               if (vdd == PRCM_VDD1)
+                       sr_start_vddautocomap(SR1, target_opp_no);
+               else if (vdd == PRCM_VDD2)
+                       sr_start_vddautocomap(SR2, target_opp_no);
+       }
+
+       return SR_PASS;
+}
+
+/* Sysfs interface to select SR VDD1 auto compensation */
+static ssize_t omap_sr_vdd1_autocomp_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", sr1.is_autocomp_active);
+}
+
+static ssize_t omap_sr_vdd1_autocomp_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t n)
+{
+       u32 current_vdd1opp_no;
+       unsigned short value;
+
+       if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
+               printk(KERN_ERR "sr_vdd1_autocomp: Invalid value\n");
+               return -EINVAL;
+       }
+
+       current_vdd1opp_no = get_opp_no(current_vdd1_opp);
+
+       if (value == 0)
+               sr_stop_vddautocomap(SR1);
+       else
+               sr_start_vddautocomap(SR1, current_vdd1opp_no);
+
+       return n;
+}
+
+static struct kobj_attribute sr_vdd1_autocomp = {
+       .attr = {
+       .name = __stringify(sr_vdd1_autocomp),
+       .mode = 0644,
+       },
+       .show = omap_sr_vdd1_autocomp_show,
+       .store = omap_sr_vdd1_autocomp_store,
+};
+
+/* Sysfs interface to select SR VDD2 auto compensation */
+static ssize_t omap_sr_vdd2_autocomp_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", sr2.is_autocomp_active);
+}
+
+static ssize_t omap_sr_vdd2_autocomp_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t n)
+{
+       u32 current_vdd2opp_no;
+       unsigned short value;
+
+       if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
+               printk(KERN_ERR "sr_vdd2_autocomp: Invalid value\n");
+               return -EINVAL;
+       }
+
+       current_vdd2opp_no = get_opp_no(current_vdd2_opp);
+
+       if (value == 0)
+               sr_stop_vddautocomap(SR2);
+       else
+               sr_start_vddautocomap(SR2, current_vdd2opp_no);
+
+       return n;
+}
+
+static struct kobj_attribute sr_vdd2_autocomp = {
+       .attr = {
+       .name = __stringify(sr_vdd2_autocomp),
+       .mode = 0644,
+       },
+       .show = omap_sr_vdd2_autocomp_show,
+       .store = omap_sr_vdd2_autocomp_store,
+};
+
+
+
+static int __init omap3_sr_init(void)
+{
+       int ret = 0;
+       u8 RdReg;
+
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               current_vdd1_opp = PRCM_VDD1_OPP3;
+               current_vdd2_opp = PRCM_VDD2_OPP3;
+       } else {
+               current_vdd1_opp = PRCM_VDD1_OPP1;
+               current_vdd2_opp = PRCM_VDD1_OPP1;
+       }
+       if (cpu_is_omap34xx()) {
+               sr_clk_init(&sr1_custom_clk);
+               sr_clk_init(&sr2_custom_clk);
+               sr1.clk = clk_get(NULL, "sr1_custom_clk");
+               sr2.clk = clk_get(NULL, "sr2_custom_clk");
+       }
+       sr_set_clk_length(&sr1);
+       sr_set_clk_length(&sr2);
+
+       /* Call the VPConfig, VCConfig, set N Values. */
+       sr_set_nvalues(&sr1);
+       sr_configure_vp(SR1);
+
+       sr_set_nvalues(&sr2);
+       sr_configure_vp(SR2);
+
+       /* Enable SR on T2 */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &RdReg,
+                                       R_DCDC_GLOBAL_CFG);
+
+       RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
+       ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, RdReg,
+                                       R_DCDC_GLOBAL_CFG);
+
+       printk(KERN_INFO "SmartReflex driver initialized\n");
+
+       ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);
+       if (ret)
+               printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
+
+       ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr);
+       if (ret)
+               printk(KERN_ERR "sysfs_create_file failed: %d\n", ret);
+
+       return 0;
+}
+
+late_initcall(omap3_sr_init);
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
new file mode 100644 (file)
index 0000000..be6e6b9
--- /dev/null
@@ -0,0 +1,259 @@
+#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+/*
+ * linux/arch/arm/mach-omap2/smartreflex.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define PHY_TO_OFF_PM_MASTER(p)                (p - 0x36)
+#define PHY_TO_OFF_PM_RECIEVER(p)      (p - 0x5b)
+#define PHY_TO_OFF_PM_INT(p)           (p - 0x2e)
+
+/* SMART REFLEX REG ADDRESS OFFSET */
+#define SRCONFIG       0x00
+#define SRSTATUS       0x04
+#define SENVAL         0x08
+#define SENMIN         0x0C
+#define SENMAX         0x10
+#define SENAVG         0x14
+#define AVGWEIGHT      0x18
+#define NVALUERECIPROCAL       0x1C
+#define SENERROR       0x20
+#define ERRCONFIG      0x24
+
+/* SR Modules */
+#define SR1            1
+#define SR2            2
+
+#define SR_FAIL                1
+#define SR_PASS                0
+
+#define SR_TRUE                1
+#define SR_FALSE       0
+
+#define GAIN_MAXLIMIT  16
+#define R_MAXLIMIT     256
+
+#define SR1_CLK_ENABLE (0x1 << 6)
+#define SR2_CLK_ENABLE (0x1 << 7)
+
+/* PRM_VP1_CONFIG */
+#define PRM_VP1_CONFIG_ERROROFFSET     (0x00 << 24)
+#define PRM_VP1_CONFIG_ERRORGAIN       (0x20 << 16)
+
+#define PRM_VP1_CONFIG_INITVOLTAGE     (0x30 << 8) /* 1.2 volt */
+#define PRM_VP1_CONFIG_TIMEOUTEN       (0x1 << 3)
+#define PRM_VP1_CONFIG_INITVDD         (0x1 << 2)
+#define PRM_VP1_CONFIG_FORCEUPDATE     (0x1 << 1)
+#define PRM_VP1_CONFIG_VPENABLE                (0x1 << 0)
+
+/* PRM_VP1_VSTEPMIN */
+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN       (0x01F4 << 8)
+#define PRM_VP1_VSTEPMIN_VSTEPMIN              (0x01 << 0)
+
+/* PRM_VP1_VSTEPMAX */
+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX       (0x01F4 << 8)
+#define PRM_VP1_VSTEPMAX_VSTEPMAX              (0x04 << 0)
+
+/* PRM_VP1_VLIMITTO */
+#define PRM_VP1_VLIMITTO_VDDMAX                (0x3C << 24)
+#define PRM_VP1_VLIMITTO_VDDMIN                (0x0 << 16)
+#define PRM_VP1_VLIMITTO_TIMEOUT       (0xFFFF << 0)
+
+/* PRM_VP2_CONFIG */
+#define PRM_VP2_CONFIG_ERROROFFSET     (0x00 << 24)
+#define PRM_VP2_CONFIG_ERRORGAIN       (0x20 << 16)
+
+#define PRM_VP2_CONFIG_INITVOLTAGE     (0x30 << 8) /* 1.2 volt */
+#define PRM_VP2_CONFIG_TIMEOUTEN       (0x1 << 3)
+#define PRM_VP2_CONFIG_INITVDD         (0x1 << 2)
+#define PRM_VP2_CONFIG_FORCEUPDATE     (0x1 << 1)
+#define PRM_VP2_CONFIG_VPENABLE                (0x1 << 0)
+
+/* PRM_VP2_VSTEPMIN */
+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN       (0x01F4 << 8)
+#define PRM_VP2_VSTEPMIN_VSTEPMIN              (0x01 << 0)
+
+/* PRM_VP2_VSTEPMAX */
+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX       (0x01F4 << 8)
+#define PRM_VP2_VSTEPMAX_VSTEPMAX              (0x04 << 0)
+
+/* PRM_VP2_VLIMITTO */
+#define PRM_VP2_VLIMITTO_VDDMAX                (0x2C << 24)
+#define PRM_VP2_VLIMITTO_VDDMIN                (0x0 << 16)
+#define PRM_VP2_VLIMITTO_TIMEOUT       (0xFFFF << 0)
+
+/* SRCONFIG */
+#define SR1_SRCONFIG_ACCUMDATA         (0x1F4 << 22)
+#define SR2_SRCONFIG_ACCUMDATA         (0x1F4 << 22)
+
+#define SRCLKLENGTH_12MHZ_SYSCLK       0x3C
+#define SRCLKLENGTH_13MHZ_SYSCLK       0x41
+#define SRCLKLENGTH_19MHZ_SYSCLK       0x60
+#define SRCLKLENGTH_26MHZ_SYSCLK       0x82
+#define SRCLKLENGTH_38MHZ_SYSCLK       0xC0
+
+#define SRCONFIG_SRCLKLENGTH_SHIFT     12
+#define SRCONFIG_SENNENABLE_SHIFT      5
+#define SRCONFIG_SENPENABLE_SHIFT      3
+
+#define SRCONFIG_SRENABLE              (0x01 << 11)
+#define SRCONFIG_SENENABLE             (0x01 << 10)
+#define SRCONFIG_ERRGEN_EN             (0x01 << 9)
+#define SRCONFIG_MINMAXAVG_EN          (0x01 << 8)
+
+#define SRCONFIG_DELAYCTRL             (0x01 << 2)
+#define SRCONFIG_CLKCTRL               (0x00 << 0)
+
+/* AVGWEIGHT */
+#define SR1_AVGWEIGHT_SENPAVGWEIGHT    (0x03 << 2)
+#define SR1_AVGWEIGHT_SENNAVGWEIGHT    (0x03 << 0)
+
+#define SR2_AVGWEIGHT_SENPAVGWEIGHT    (0x01 << 2)
+#define SR2_AVGWEIGHT_SENNAVGWEIGHT    (0x01 << 0)
+
+/* NVALUERECIPROCAL */
+#define NVALUERECIPROCAL_SENPGAIN_SHIFT        20
+#define NVALUERECIPROCAL_SENNGAIN_SHIFT        16
+#define NVALUERECIPROCAL_RNSENP_SHIFT  8
+#define NVALUERECIPROCAL_RNSENN_SHIFT  0
+
+/* ERRCONFIG */
+#define SR_CLKACTIVITY_MASK            (0x03 << 20)
+#define SR_ERRWEIGHT_MASK              (0x07 << 16)
+#define SR_ERRMAXLIMIT_MASK            (0xFF << 8)
+#define SR_ERRMINLIMIT_MASK            (0xFF << 0)
+
+#define SR_CLKACTIVITY_IOFF_FOFF       (0x00 << 20)
+#define SR_CLKACTIVITY_IOFF_FON                (0x02 << 20)
+
+#define ERRCONFIG_VPBOUNDINTEN         (0x1 << 31)
+#define ERRCONFIG_VPBOUNDINTST         (0x1 << 30)
+
+#define SR1_ERRWEIGHT                  (0x07 << 16)
+#define SR1_ERRMAXLIMIT                        (0x02 << 8)
+#define SR1_ERRMINLIMIT                        (0xFA << 0)
+
+#define SR2_ERRWEIGHT                  (0x07 << 16)
+#define SR2_ERRMAXLIMIT                        (0x02 << 8)
+#define SR2_ERRMINLIMIT                        (0xF9 << 0)
+
+/* T2 SMART REFLEX */
+#define R_SRI2C_SLAVE_ADDR             0x12
+#define R_VDD1_SR_CONTROL              0x00
+#define R_VDD2_SR_CONTROL              0x01
+#define T2_SMPS_UPDATE_DELAY           360     /* In uSec */
+
+/* Vmode control */
+#define R_DCDC_GLOBAL_CFG      PHY_TO_OFF_PM_RECIEVER(0x61)
+
+#define R_VDD1_VSEL            PHY_TO_OFF_PM_RECIEVER(0xb9)
+#define R_VDD1_VMODE_CFG       PHY_TO_OFF_PM_RECIEVER(0xba)
+#define R_VDD1_VFLOOR          PHY_TO_OFF_PM_RECIEVER(0xbb)
+#define R_VDD1_VROOF           PHY_TO_OFF_PM_RECIEVER(0xbc)
+#define R_VDD1_STEP            PHY_TO_OFF_PM_RECIEVER(0xbd)
+
+#define R_VDD2_VSEL            PHY_TO_OFF_PM_RECIEVER(0xc7)
+#define R_VDD2_VMODE_CFG       PHY_TO_OFF_PM_RECIEVER(0xc8)
+#define R_VDD2_VFLOOR          PHY_TO_OFF_PM_RECIEVER(0xc9)
+#define R_VDD2_VROOF           PHY_TO_OFF_PM_RECIEVER(0xca)
+#define R_VDD2_STEP            PHY_TO_OFF_PM_RECIEVER(0xcb)
+
+/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */
+#define DCDC_GLOBAL_CFG_ENABLE_SRFLX   0x08
+
+/* VDDs*/
+#define PRCM_VDD1      1
+#define PRCM_VDD2      2
+#define PRCM_MAX_SYSC_REGS 30
+
+/*
+ * XXX: These should be removed/moved from here once we have a working DVFS
+ * implementation in place
+ */
+#define AT_3430                1       /*3430 ES 1.0 */
+#define AT_3430_ES2    2       /*3430 ES 2.0 */
+
+#define ID_OPP                 0xE2    /*OPP*/
+
+/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */
+#define OMAP_TYPE_SHIFT                28
+#define OMAP_TYPE_MASK         0xF
+/* OPP ID: bits: 0-4 for OPP number */
+#define OPP_NO_POS             0
+#define OPP_NO_MASK            0x1F
+/* OPP ID: bits: 5-6 for VDD */
+#define VDD_NO_POS             5
+#define VDD_NO_MASK            0x3
+/* Other IDs: bits 20-27 for ID type */
+/* These IDs have bits 25,26,27 as 1 */
+#define OTHER_ID_TYPE_SHIFT            20
+#define OTHER_ID_TYPE_MASK             0xFF
+
+#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT)
+#define ID_OPP_NO(X)    ((X & OPP_NO_MASK) << OPP_NO_POS)
+#define ID_VDD(X)       ((X & VDD_NO_MASK) << VDD_NO_POS)
+#define OMAP(X)                 ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK)
+#define get_opp_no(X)   ((X >> OPP_NO_POS) & OPP_NO_MASK)
+#define get_vdd(X)      ((X >> VDD_NO_POS) & VDD_NO_MASK)
+
+/* VDD1 OPPs */
+#define PRCM_VDD1_OPP1         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x1))
+#define PRCM_VDD1_OPP2         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x2))
+#define PRCM_VDD1_OPP3         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x3))
+#define PRCM_VDD1_OPP4         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x4))
+#define PRCM_VDD1_OPP5         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD1) | ID_OPP_NO(0x5))
+#define PRCM_NO_VDD1_OPPS      5
+
+
+/* VDD2 OPPs */
+#define PRCM_VDD2_OPP1         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x1))
+#define PRCM_VDD2_OPP2         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x2))
+#define PRCM_VDD2_OPP3         (OMAP(AT_3430_ES2) | OTHER_ID_TYPE(ID_OPP) | \
+                                       ID_VDD(PRCM_VDD2) | ID_OPP_NO(0x3))
+#define PRCM_NO_VDD2_OPPS      3
+/* XXX: end remove/move */
+
+/* XXX: find more appropriate place for these once DVFS is in place */
+extern u32 current_vdd1_opp;
+extern u32 current_vdd2_opp;
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING
+#define SR_TESTING_NVALUES     1
+#else
+#define SR_TESTING_NVALUES     0
+#endif
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+#ifdef CONFIG_OMAP_SMARTREFLEX
+void enable_smartreflex(int srid);
+void disable_smartreflex(int srid);
+int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel);
+void sr_start_vddautocomap(int srid, u32 target_opp_no);
+int sr_stop_vddautocomap(int srid);
+#else
+static inline void enable_smartreflex(int srid) {}
+static inline void disable_smartreflex(int srid) {}
+#endif
+
+#endif
index af4bd3490227feddda1cca44702bc32eb03caf6b..a2086c3804ef8decda94a2d37c67560fac975e66 100644 (file)
 #include "cm.h"
 #include "sdrc.h"
 
+#define OMAP242X_PRCM_VOLTCTRL         OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
+                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
+#define OMAP242X_PRCM_CLKCFG_CTRL      OMAP2420_PRM_REGADDR(OMAP24XX_GR_MOD,   \
+                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+
        .text
 
 ENTRY(omap242x_sram_ddr_init)
index 84363e269e8cd7fca6418765786074e4db5e2967..7946a5ff58a9116da0b9163182f1efcb483f6518 100644 (file)
 #include "cm.h"
 #include "sdrc.h"
 
+#define OMAP243X_PRCM_VOLTCTRL         OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
+                                               OMAP24XX_PRCM_VOLTCTRL_OFFSET)
+#define OMAP243X_PRCM_CLKCFG_CTRL      OMAP2430_PRM_REGADDR(OMAP24XX_GR_MOD,   \
+                                               OMAP24XX_PRCM_CLKCFG_CTRL_OFFSET)
+
        .text
 
 ENTRY(omap243x_sram_ddr_init)
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
new file mode 100644 (file)
index 0000000..2c71461
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * linux/arch/arm/mach-omap3/sram.S
+ *
+ * Omap3 specific functions that need to be run in internal SRAM
+ *
+ * (C) Copyright 2007
+ * Texas Instruments Inc.
+ * Rajendra Nayak <rnayak@ti.com>
+ *
+ * (C) Copyright 2004
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+
+#include <mach/io.h>
+
+#include "sdrc.h"
+#include "cm.h"
+
+       .text
+
+/*
+ * Change frequency of core dpll
+ * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2
+ */
+ENTRY(omap3_sram_configure_core_dpll)
+       stmfd   sp!, {r1-r12, lr}       @ store regs to stack
+       cmp     r3, #0x2
+       blne    configure_sdrc
+       cmp     r3, #0x2
+       blne    lock_dll
+       cmp     r3, #0x1
+       blne    unlock_dll
+       bl      sdram_in_selfrefresh    @ put the SDRAM in self refresh
+       bl      configure_core_dpll
+       bl      enable_sdrc
+       cmp     r3, #0x1
+       blne    wait_dll_unlock
+       cmp     r3, #0x2
+       blne    wait_dll_lock
+       cmp     r3, #0x1
+       blne    configure_sdrc
+       mov     r0, #0                  @ return value
+       ldmfd   sp!, {r1-r12, pc}       @ restore regs and return
+unlock_dll:
+       ldr     r4, omap3_sdrc_dlla_ctrl
+       ldr     r5, [r4]
+       orr     r5, r5, #0x4
+       str     r5, [r4]
+       bx      lr
+lock_dll:
+       ldr     r4, omap3_sdrc_dlla_ctrl
+       ldr     r5, [r4]
+       bic     r5, r5, #0x4
+       str     r5, [r4]
+       bx      lr
+sdram_in_selfrefresh:
+       mov     r5, #0x0                @ Move 0 to R5
+       mcr     p15, 0, r5, c7, c10, 5  @ memory barrier
+       ldr     r4, omap3_sdrc_power    @ read the SDRC_POWER register
+       ldr     r5, [r4]                @ read the contents of SDRC_POWER
+       orr     r5, r5, #0x40           @ enable self refresh on idle req
+       str     r5, [r4]                @ write back to SDRC_POWER register
+       ldr     r4, omap3_cm_iclken1_core       @ read the CM_ICLKEN1_CORE reg
+       ldr     r5, [r4]
+       bic     r5, r5, #0x2            @ disable iclk bit for SRDC
+       str     r5, [r4]
+wait_sdrc_idle:
+       ldr     r4, omap3_cm_idlest1_core
+       ldr     r5, [r4]
+       and     r5, r5, #0x2            @ check for SDRC idle
+       cmp     r5, #2
+       bne     wait_sdrc_idle
+       bx      lr
+configure_core_dpll:
+       ldr     r4, omap3_cm_clksel1_pll
+       ldr     r5, [r4]
+       ldr     r6, core_m2_mask_val    @ modify m2 for core dpll
+       and     r5, r5, r6
+       orr     r5, r5, r3, lsl #0x1B   @ r3 contains the M2 val
+       str     r5, [r4]
+       mov     r5, #0x800              @ wait for the clock to stabilise
+       cmp     r3, #2
+       bne     wait_clk_stable
+       bx      lr
+wait_clk_stable:
+       subs    r5, r5, #1
+       bne     wait_clk_stable
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       bx      lr
+enable_sdrc:
+       ldr     r4, omap3_cm_iclken1_core
+       ldr     r5, [r4]
+       orr     r5, r5, #0x2            @ enable iclk bit for SDRC
+       str     r5, [r4]
+wait_sdrc_idle1:
+       ldr     r4, omap3_cm_idlest1_core
+       ldr     r5, [r4]
+       and     r5, r5, #0x2
+       cmp     r5, #0
+       bne     wait_sdrc_idle1
+       ldr     r4, omap3_sdrc_power
+       ldr     r5, [r4]
+       bic     r5, r5, #0x40
+       str     r5, [r4]
+       bx      lr
+wait_dll_lock:
+       ldr     r4, omap3_sdrc_dlla_status
+       ldr     r5, [r4]
+       and     r5, r5, #0x4
+       cmp     r5, #0x4
+       bne     wait_dll_lock
+       bx      lr
+wait_dll_unlock:
+       ldr     r4, omap3_sdrc_dlla_status
+       ldr     r5, [r4]
+       and     r5, r5, #0x4
+       cmp     r5, #0x0
+       bne     wait_dll_unlock
+       bx      lr
+configure_sdrc:
+       ldr     r4, omap3_sdrc_rfr_ctrl
+       str     r0, [r4]
+       ldr     r4, omap3_sdrc_actim_ctrla
+       str     r1, [r4]
+       ldr     r4, omap3_sdrc_actim_ctrlb
+       str     r2, [r4]
+       bx      lr
+
+omap3_sdrc_power:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+omap3_cm_clksel1_pll:
+       .word OMAP34XX_CM_REGADDR(PLL_MOD, CM_CLKSEL1)
+omap3_cm_idlest1_core:
+       .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
+omap3_cm_iclken1_core:
+       .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
+omap3_sdrc_rfr_ctrl:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0)
+omap3_sdrc_actim_ctrla:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0)
+omap3_sdrc_actim_ctrlb:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0)
+omap3_sdrc_dlla_status:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
+omap3_sdrc_dlla_ctrl:
+       .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+core_m2_mask_val:
+       .word 0x07FFFFFF
+
+ENTRY(omap3_sram_configure_core_dpll_sz)
+       .word   . - omap3_sram_configure_core_dpll
index 589393bedade0477dbecb909d5fd82501a58203c..787cfef7b3bbc6c44179cf6de60ca5fe04f04d79 100644 (file)
@@ -99,7 +99,7 @@ static void __init omap2_gp_clockevent_init(void)
 {
        u32 tick_rate;
 
-       gptimer = omap_dm_timer_request_specific(1);
+       gptimer = omap_dm_timer_request_specific(CONFIG_OMAP_TICK_GPTIMER);
        BUG_ON(gptimer == NULL);
 
 #if defined(CONFIG_OMAP_32K_TIMER)
@@ -109,6 +109,9 @@ static void __init omap2_gp_clockevent_init(void)
 #endif
        tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
 
+       pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
+               CONFIG_OMAP_TICK_GPTIMER, tick_rate);
+
        omap2_gp_timer_irq.dev_id = (void *)gptimer;
        setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
        omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
new file mode 100644 (file)
index 0000000..489439d
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * linux/arch/arm/mach-omap2/usb-ehci.c
+ *
+ * This file will contain the board specific details for the
+ * Synopsys EHCI host controller on OMAP3430
+ *
+ * Copyright (C) 2007 Texas Instruments
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * Generalization by:
+ * Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <mach/mux.h>
+#include <linux/usb/musb.h>
+
+#include <mach/hardware.h>
+#include <mach/pm.h>
+#include <mach/usb.h>
+
+#if    defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+static struct resource ehci_resources[] = {
+       [0] = {
+               .start   = OMAP34XX_HSUSB_HOST_BASE + 0x800,
+               .end     = OMAP34XX_HSUSB_HOST_BASE + 0x800 + SZ_1K - 1,
+               .flags   = IORESOURCE_MEM,
+       },
+       [1] = {         /* general IRQ */
+               .start   = INT_34XX_EHCI_IRQ,
+               .flags   = IORESOURCE_IRQ,
+       }
+};
+
+static u64 ehci_dmamask = ~(u32)0;
+static struct platform_device ehci_device = {
+       .name           = "ehci-omap",
+       .id             = 0,
+       .dev = {
+               .dma_mask               = &ehci_dmamask,
+               .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = NULL,
+       },
+       .num_resources  = ARRAY_SIZE(ehci_resources),
+       .resource       = ehci_resources,
+};
+
+
+/* MUX settings for EHCI pins */
+/*
+ * setup_ehci_io_mux - initialize IO pad mux for USBHOST
+ */
+static void setup_ehci_io_mux(void)
+{
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+       /* PHY mode of operation for board: 750-2083-001
+        * ISP1504 connected to Port1 and Port2
+        * Do Func Mux setting for 12-pin ULPI PHY mode
+        */
+
+       /* Port1 */
+       omap_cfg_reg(Y9_3430_USB1HS_PHY_STP);
+       omap_cfg_reg(Y8_3430_USB1HS_PHY_CLK);
+       omap_cfg_reg(AA14_3430_USB1HS_PHY_DIR);
+       omap_cfg_reg(AA11_3430_USB1HS_PHY_NXT);
+       omap_cfg_reg(W13_3430_USB1HS_PHY_DATA0);
+       omap_cfg_reg(W12_3430_USB1HS_PHY_DATA1);
+       omap_cfg_reg(W11_3430_USB1HS_PHY_DATA2);
+       omap_cfg_reg(Y11_3430_USB1HS_PHY_DATA3);
+       omap_cfg_reg(W9_3430_USB1HS_PHY_DATA4);
+       omap_cfg_reg(Y12_3430_USB1HS_PHY_DATA5);
+       omap_cfg_reg(W8_3430_USB1HS_PHY_DATA6);
+       omap_cfg_reg(Y13_3430_USB1HS_PHY_DATA7);
+
+       /* Port2 */
+       omap_cfg_reg(AA10_3430_USB2HS_PHY_STP);
+       omap_cfg_reg(AA8_3430_USB2HS_PHY_CLK);
+       omap_cfg_reg(AA9_3430_USB2HS_PHY_DIR);
+       omap_cfg_reg(AB11_3430_USB2HS_PHY_NXT);
+       omap_cfg_reg(AB10_3430_USB2HS_PHY_DATA0);
+       omap_cfg_reg(AB9_3430_USB2HS_PHY_DATA1);
+       omap_cfg_reg(W3_3430_USB2HS_PHY_DATA2);
+       omap_cfg_reg(T4_3430_USB2HS_PHY_DATA3);
+       omap_cfg_reg(T3_3430_USB2HS_PHY_DATA4);
+       omap_cfg_reg(R3_3430_USB2HS_PHY_DATA5);
+       omap_cfg_reg(R4_3430_USB2HS_PHY_DATA6);
+       omap_cfg_reg(T2_3430_USB2HS_PHY_DATA7);
+
+#else
+       /* Set Func mux for :
+        * TLL mode of operation
+        * 12-pin ULPI SDR TLL mode for Port1/2/3
+        */
+
+       /* Port1 */
+       omap_cfg_reg(Y9_3430_USB1HS_TLL_STP);
+       omap_cfg_reg(Y8_3430_USB1HS_TLL_CLK);
+       omap_cfg_reg(AA14_3430_USB1HS_TLL_DIR);
+       omap_cfg_reg(AA11_3430_USB1HS_TLL_NXT);
+       omap_cfg_reg(W13_3430_USB1HS_TLL_DATA0);
+       omap_cfg_reg(W12_3430_USB1HS_TLL_DATA1);
+       omap_cfg_reg(W11_3430_USB1HS_TLL_DATA2);
+       omap_cfg_reg(Y11_3430_USB1HS_TLL_DATA3);
+       omap_cfg_reg(W9_3430_USB1HS_TLL_DATA4);
+       omap_cfg_reg(Y12_3430_USB1HS_TLL_DATA5);
+       omap_cfg_reg(W8_3430_USB1HS_TLL_DATA6);
+       omap_cfg_reg(Y13_3430_USB1HS_TLL_DATA7);
+
+       /* Port2 */
+       omap_cfg_reg(AA10_3430_USB2HS_TLL_STP);
+       omap_cfg_reg(AA8_3430_USB2HS_TLL_CLK);
+       omap_cfg_reg(AA9_3430_USB2HS_TLL_DIR);
+       omap_cfg_reg(AB11_3430_USB2HS_TLL_NXT);
+       omap_cfg_reg(AB10_3430_USB2HS_TLL_DATA0);
+       omap_cfg_reg(AB9_3430_USB2HS_TLL_DATA1);
+       omap_cfg_reg(W3_3430_USB2HS_TLL_DATA2);
+       omap_cfg_reg(T4_3430_USB2HS_TLL_DATA3);
+       omap_cfg_reg(T3_3430_USB2HS_TLL_DATA4);
+       omap_cfg_reg(R3_3430_USB2HS_TLL_DATA5);
+       omap_cfg_reg(R4_3430_USB2HS_TLL_DATA6);
+       omap_cfg_reg(T2_3430_USB2HS_TLL_DATA7);
+
+       /* Port3 */
+       omap_cfg_reg(AB3_3430_USB3HS_TLL_STP);
+       omap_cfg_reg(AA6_3430_USB3HS_TLL_CLK);
+       omap_cfg_reg(AA3_3430_USB3HS_TLL_DIR);
+       omap_cfg_reg(Y3_3430_USB3HS_TLL_NXT);
+       omap_cfg_reg(AA5_3430_USB3HS_TLL_DATA0);
+       omap_cfg_reg(Y4_3430_USB3HS_TLL_DATA1);
+       omap_cfg_reg(Y5_3430_USB3HS_TLL_DATA2);
+       omap_cfg_reg(W5_3430_USB3HS_TLL_DATA3);
+       omap_cfg_reg(AB12_3430_USB3HS_TLL_DATA4);
+       omap_cfg_reg(AB13_3430_USB3HS_TLL_DATA5);
+       omap_cfg_reg(AA13_3430_USB3HS_TLL_DATA6);
+       omap_cfg_reg(AA12_3430_USB3HS_TLL_DATA7);
+#endif /* CONFIG_OMAP_EHCI_PHY_MODE */
+
+       return;
+}
+
+#endif /* EHCI specific data */
+
+void __init usb_ehci_init(void)
+{
+#if     defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
+       /* Setup Pin IO MUX for EHCI */
+       if (cpu_is_omap34xx())
+               setup_ehci_io_mux();
+
+       if (platform_device_register(&ehci_device) < 0) {
+               printk(KERN_ERR "Unable to register HS-USB (EHCI) device\n");
+               return;
+       }
+#endif
+}
+
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
new file mode 100644 (file)
index 0000000..61c5709
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * linux/arch/arm/mach-omap2/usb-musb.c
+ *
+ * This file will contain the board specific details for the
+ * MENTOR USB OTG controller on OMAP3430
+ *
+ * Copyright (C) 2007-2008 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: Vikram Pandita
+ *
+ * Generalization by:
+ * Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+
+#include <linux/usb/musb.h>
+
+#include <mach/hardware.h>
+#include <mach/pm.h>
+#include <mach/mux.h>
+#include <mach/usb.h>
+
+#ifdef CONFIG_USB_MUSB_SOC
+static struct resource musb_resources[] = {
+       [0] = {
+               .start  = cpu_is_omap34xx()
+                       ? OMAP34XX_HSUSB_OTG_BASE
+                       : OMAP243X_HS_BASE,
+               .end    = cpu_is_omap34xx()
+                       ? OMAP34XX_HSUSB_OTG_BASE + SZ_8K - 1
+                       : OMAP243X_HS_BASE + SZ_8K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = { /* general IRQ */
+               .start  = INT_243X_HS_USB_MC,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = { /* DMA IRQ */
+               .start  = INT_243X_HS_USB_DMA,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static int clk_on;
+
+static int musb_set_clock(struct clk *clk, int state)
+{
+       if (state) {
+               if (clk_on > 0)
+                       return -ENODEV;
+
+               clk_enable(clk);
+               clk_on = 1;
+       } else {
+               if (clk_on == 0)
+                       return -ENODEV;
+
+               clk_disable(clk);
+               clk_on = 0;
+       }
+
+       return 0;
+}
+
+static struct musb_hdrc_eps_bits musb_eps[] = {
+       {       "ep1_tx", 10,   },
+       {       "ep1_rx", 10,   },
+       {       "ep2_tx", 9,    },
+       {       "ep2_rx", 9,    },
+       {       "ep3_tx", 3,    },
+       {       "ep3_rx", 3,    },
+       {       "ep4_tx", 3,    },
+       {       "ep4_rx", 3,    },
+       {       "ep5_tx", 3,    },
+       {       "ep5_rx", 3,    },
+       {       "ep6_tx", 3,    },
+       {       "ep6_rx", 3,    },
+       {       "ep7_tx", 3,    },
+       {       "ep7_rx", 3,    },
+       {       "ep8_tx", 2,    },
+       {       "ep8_rx", 2,    },
+       {       "ep9_tx", 2,    },
+       {       "ep9_rx", 2,    },
+       {       "ep10_tx", 2,   },
+       {       "ep10_rx", 2,   },
+       {       "ep11_tx", 2,   },
+       {       "ep11_rx", 2,   },
+       {       "ep12_tx", 2,   },
+       {       "ep12_rx", 2,   },
+       {       "ep13_tx", 2,   },
+       {       "ep13_rx", 2,   },
+       {       "ep14_tx", 2,   },
+       {       "ep14_rx", 2,   },
+       {       "ep15_tx", 2,   },
+       {       "ep15_rx", 2,   },
+};
+
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = 1,
+       .dyn_fifo       = 1,
+       .soft_con       = 1,
+       .dma            = 1,
+       .num_eps        = 16,
+       .dma_channels   = 7,
+       .dma_req_chan   = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
+       .ram_bits       = 12,
+       .eps_bits       = musb_eps,
+};
+
+static struct musb_hdrc_platform_data musb_plat = {
+#ifdef CONFIG_USB_MUSB_OTG
+       .mode           = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_HDRC_HCD)
+       .mode           = MUSB_HOST,
+#elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
+       .mode           = MUSB_PERIPHERAL,
+#endif
+       .clock          = cpu_is_omap34xx()
+                       ? "hsotgusb_ick"
+                       : "usbhs_ick",
+       .set_clock      = musb_set_clock,
+       .config         = &musb_config,
+
+       /* REVISIT charge pump on TWL4030 can supply up to
+        * 100 mA ... but this value is board-specific, like
+        * "mode", and should be passed to usb_musb_init().
+        */
+       .power          = 50,                   /* up to 100 mA */
+};
+
+static u64 musb_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device musb_device = {
+       .name           = "musb_hdrc",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = &musb_dmamask,
+               .coherent_dma_mask      = DMA_32BIT_MASK,
+               .platform_data          = &musb_plat,
+       },
+       .num_resources  = ARRAY_SIZE(musb_resources),
+       .resource       = musb_resources,
+};
+#endif
+
+
+void __init usb_musb_init(void)
+{
+#ifdef CONFIG_USB_MUSB_SOC
+       if (platform_device_register(&musb_device) < 0) {
+               printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
+               return;
+       }
+#endif
+}
+
index 10ef464d6be7f3f2768a1a7d95d6adb68e88ed17..2c88207fc50d2f7ec91c1aa7bcefade74a7a2c53 100644 (file)
@@ -175,8 +175,6 @@ static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned 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)
 {
index ed15f876c7254cd02ea86d53b5346cfa4efc67d0..546d7e7db74e63685c4f659e46f504555382d965 100644 (file)
@@ -428,7 +428,7 @@ config CPU_32v6K
 # ARMv7
 config CPU_V7
        bool "Support ARM V7 processor"
-       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB
+       depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP3
        select CPU_32v6K
        select CPU_32v7
        select CPU_ABRT_EV7
index b917206ee9068036f6e17570162595a16afbdf38..960c13fd3b33d2d4b94b0ac19a83a9609a8ac7ad 100644 (file)
@@ -15,6 +15,9 @@ config ARCH_OMAP1
 config ARCH_OMAP2
        bool "TI OMAP2"
 
+config ARCH_OMAP3
+       bool "TI OMAP3"
+
 endchoice
 
 comment "OMAP Feature Selections"
@@ -29,6 +32,61 @@ config OMAP_DEBUG_LEDS
        depends on OMAP_DEBUG_DEVICES
        default y if LEDS || LEDS_OMAP_DEBUG
 
+config OMAP_DEBUG_POWERDOMAIN
+       bool "Emit debug messages from powerdomain layer"
+       depends on ARCH_OMAP2 || ARCH_OMAP3
+       default n
+       help
+         Say Y here if you want to compile in powerdomain layer
+         debugging messages for OMAP2/3.   These messages can
+         provide more detail as to why some powerdomain calls
+         may be failing, and will also emit a descriptive message
+         for every powerdomain register write.  However, the
+         extra detail costs some memory.
+
+config OMAP_DEBUG_CLOCKDOMAIN
+       bool "Emit debug messages from clockdomain layer"
+       depends on ARCH_OMAP2 || ARCH_OMAP3
+       default n
+       help
+         Say Y here if you want to compile in clockdomain layer
+         debugging messages for OMAP2/3.   These messages can
+         provide more detail as to why some clockdomain calls
+         may be failing, and will also emit a descriptive message
+         for every clockdomain register write.  However, the
+         extra detail costs some memory.
+
+config OMAP_SMARTREFLEX
+       bool "SmartReflex support"
+       depends on ARCH_OMAP34XX && TWL4030_CORE
+       help
+         Say Y if you want to enable SmartReflex.
+
+         SmartReflex can perform continuous dynamic voltage
+         scaling around the nominal operating point voltage
+         according to silicon characteristics and operating
+         conditions. Enabling SmartReflex reduces power
+         consumption.
+
+         Please note, that by default SmartReflex is only
+         initialized. To enable the automatic voltage
+         compensation for VDD1 and VDD2, user must write 1 to
+         /sys/power/sr_vddX_autocomp, where X is 1 or 2.
+
+config OMAP_SMARTREFLEX_TESTING
+       bool "Smartreflex testing support"
+       depends on OMAP_SMARTREFLEX
+       default n
+       help
+         Say Y if you want to enable SmartReflex testing with SW hardcoded
+         NVALUES intead of E-fuse NVALUES set in factory silicon testing.
+
+         In some devices the E-fuse values have not been set, even though
+         SmartReflex modules are included. Using these hardcoded values set
+         in software, one can test the SmartReflex features without E-fuse.
+
+         WARNING: Enabling this option may cause your device to hang!
+
 config OMAP_RESET_CLOCKS
        bool "Reset unused clocks during boot"
        depends on ARCH_OMAP
@@ -41,6 +99,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
@@ -75,6 +166,22 @@ config OMAP_MCBSP
          Say Y here if you want support for the OMAP Multichannel
          Buffered Serial Port.
 
+config OMAP_MMU_FWK
+       bool "MMU framework support"
+       depends on ARCH_OMAP
+       default n
+       help
+         Say Y here if you want to use OMAP MMU framework support for
+         DSP, IVA1.0 and Camera in OMAP1/2.
+
+config OMAP_MBOX_FWK
+       tristate "Mailbox framework support"
+       depends on ARCH_OMAP
+       default n
+       help
+         Say Y here if you want to use OMAP Mailbox framework support for
+         DSP and IVA1.0 in OMAP1/2.
+
 choice
         prompt "System timer"
        default OMAP_MPU_TIMER
@@ -88,13 +195,13 @@ config OMAP_MPU_TIMER
 
 config OMAP_32K_TIMER
        bool "Use 32KHz timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
          Select this option if you want to enable the OMAP 32KHz timer.
          This timer saves power compared to the OMAP_MPU_TIMER, and has
          support for no tick during idle. The 32KHz timer provides less
          intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
-         currently only available for OMAP16XX and 24XX.
+         currently only available for OMAP16XX, 24XX and 34XX.
 
 endchoice
 
@@ -109,7 +216,7 @@ config OMAP_32K_TIMER_HZ
 
 config OMAP_DM_TIMER
        bool "Use dual-mode timer"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
         Select this option if you want to use OMAP Dual-Mode timers.
 
index 2c4051cc79a13f249e32d4cb6abf31841ee1c258..12598461105618b0596c507ee7b7ff75560e741b 100644 (file)
@@ -4,7 +4,7 @@
 
 # Common support
 obj-y := common.o sram.o clock.o devices.o dma.o mux.o gpio.o \
-        usb.o fb.o
+        usb.o fb.o io.o
 obj-m :=
 obj-n :=
 obj-  :=
@@ -16,10 +16,16 @@ 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
 obj-$(CONFIG_I2C_OMAP) += i2c.o
 
+# OMAP MMU framework
+obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o
+
 # OMAP mailbox framework
 obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o
 
diff --git a/arch/arm/plat-omap/bootreason.c b/arch/arm/plat-omap/bootreason.c
new file mode 100644 (file)
index 0000000..d527b1b
--- /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 <mach/board.h>
+
+static char boot_reason[16];
+
+static int omap_bootreason_read_proc(char *page, char **start, off_t off,
+                                        int count, int *eof, void *data)
+{
+       int len = 0;
+
+       len += sprintf(page + len, "%s\n", boot_reason);
+
+       *start = page + off;
+
+       if (len > off)
+               len -= off;
+       else
+               len = 0;
+
+       return len < count ? len  : count;
+}
+
+static int __init bootreason_init(void)
+{
+       const struct omap_boot_reason_config *cfg;
+       int reason_valid = 0;
+
+       cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config);
+       if (cfg != NULL) {
+               strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str));
+               boot_reason[sizeof(cfg->reason_str)] = 0;
+               reason_valid = 1;
+       } else {
+               /* Read the boot reason from the OMAP registers */
+       }
+
+       if (!reason_valid)
+               return -ENOENT;
+
+       printk(KERN_INFO "Bootup reason: %s\n", boot_reason);
+
+       if (!create_proc_read_entry("bootreason", S_IRUGO, NULL,
+                                       omap_bootreason_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+late_initcall(bootreason_init);
index 197974defbe4f4b0e41ffebf2aae1f2c96dc6c00..7bbfba2a5c1e11949e717bee6d68bd37abcf7fd8 100644 (file)
@@ -384,8 +384,11 @@ static int __init clk_disable_unused(void)
        unsigned long flags;
 
        list_for_each_entry(ck, &clocks, node) {
-               if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
-                       ck->enable_reg == 0)
+               if (ck->usecount > 0 ||
+                   (ck->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)))
+                       continue;
+
+               if (cpu_class_is_omap1() && ck->enable_reg == 0)
                        continue;
 
                spin_lock_irqsave(&clockfw_lock, flags);
index f4dff423ae7c19569adf3302f7851a527b595360..f498a23ba0640ec36e56f11690a2580a51b18e28 100644 (file)
 
 #define NO_LENGTH_CHECK 0xffffffff
 
-unsigned char omap_bootloader_tag[512];
+unsigned char omap_bootloader_tag[1024];
 int omap_bootloader_tag_len;
 
 struct omap_board_config_kernel *omap_board_config;
 int omap_board_config_size;
 
+#ifdef CONFIG_OMAP_BOOT_TAG
+
+static int __init parse_tag_omap(const struct tag *tag)
+{
+       u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2);
+
+        size <<= 2;
+       if (size > sizeof(omap_bootloader_tag))
+               return -1;
+
+       memcpy(omap_bootloader_tag, tag->u.omap.data, size);
+       omap_bootloader_tag_len = size;
+
+        return 0;
+}
+
+__tagtable(ATAG_BOARD, parse_tag_omap);
+
+#endif
+
 static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
 {
        struct omap_board_config_kernel *kinfo = NULL;
@@ -248,7 +268,8 @@ static struct omap_globals *omap2_globals;
 
 static void __init __omap2_set_globals(void)
 {
-       omap2_set_globals_memory(omap2_globals);
+       omap2_set_globals_tap(omap2_globals);
+       omap2_set_globals_sdrc(omap2_globals);
        omap2_set_globals_control(omap2_globals);
        omap2_set_globals_prcm(omap2_globals);
 }
@@ -258,12 +279,13 @@ static void __init __omap2_set_globals(void)
 #if defined(CONFIG_ARCH_OMAP2420)
 
 static struct omap_globals omap242x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x48014000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
+       .class  = OMAP242X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x48014000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP2420_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP2420_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP2420_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP2420_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP2420_CM_BASE),
 };
 
 void __init omap2_set_globals_242x(void)
@@ -276,12 +298,13 @@ void __init omap2_set_globals_242x(void)
 #if defined(CONFIG_ARCH_OMAP2430)
 
 static struct omap_globals omap243x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x4900a000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
+       .class  = OMAP243X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x4900a000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP243X_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP243X_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP243X_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP2430_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP2430_CM_BASE),
 };
 
 void __init omap2_set_globals_243x(void)
@@ -294,12 +317,13 @@ void __init omap2_set_globals_243x(void)
 #if defined(CONFIG_ARCH_OMAP3430)
 
 static struct omap_globals omap343x_globals = {
-       .tap    = (__force void __iomem *)OMAP2_IO_ADDRESS(0x4830A000),
-       .sdrc   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
-       .sms    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
-       .ctrl   = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
-       .prm    = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
-       .cm     = (__force void __iomem *)OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
+       .class  = OMAP343X_CLASS,
+       .tap    = OMAP2_IO_ADDRESS(0x4830A000),
+       .sdrc   = OMAP2_IO_ADDRESS(OMAP343X_SDRC_BASE),
+       .sms    = OMAP2_IO_ADDRESS(OMAP343X_SMS_BASE),
+       .ctrl   = OMAP2_IO_ADDRESS(OMAP343X_CTRL_BASE),
+       .prm    = OMAP2_IO_ADDRESS(OMAP3430_PRM_BASE),
+       .cm     = OMAP2_IO_ADDRESS(OMAP3430_CM_BASE),
 };
 
 void __init omap2_set_globals_343x(void)
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..3c9d523
--- /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 <mach/board.h>
+#include <mach/board-nokia.h>
+
+static int component_version_read_proc(char *page, char **start, off_t off,
+                                      int count, int *eof, void *data)
+{
+       int len, i;
+       const struct omap_version_config *ver;
+       char *p;
+
+       i = 0;
+       p = page;
+       while ((ver = omap_get_nr_config(OMAP_TAG_VERSION_STR,
+                                        struct omap_version_config, i)) != NULL) {
+               p += sprintf(p, "%-12s%s\n", ver->component, ver->version);
+               i++;
+       }
+
+       len = (p - page) - off;
+       if (len < 0)
+               len = 0;
+
+       *eof = (len <= count) ? 1 : 0;
+       *start = page + off;
+
+       return len;
+}
+
+static int __init component_version_init(void)
+{
+       if (omap_get_config(OMAP_TAG_VERSION_STR, struct omap_version_config) == NULL)
+               return -ENODEV;
+       if (!create_proc_read_entry("component_version", S_IRUGO, NULL,
+                                   component_version_read_proc, NULL))
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __exit component_version_exit(void)
+{
+       remove_proc_entry("component_version", NULL);
+}
+
+late_initcall(component_version_init);
+module_exit(component_version_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
+MODULE_DESCRIPTION("Component version driver");
+MODULE_LICENSE("GPL");
index ae1de308aaad2e5c9db136e8c9ed3d4841db976d..dbfcca908519c0d4e89e77261c1c1df6130bff4a 100644 (file)
 #include <mach/hardware.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <mach/clock.h>
 
 #define VERY_HI_RATE   900000000
 
+static struct cpufreq_frequency_table *freq_table;
+
 #ifdef CONFIG_ARCH_OMAP1
 #define MPU_CLK                "mpu"
 #else
@@ -39,6 +42,9 @@ static struct clk *mpu_clk;
 
 int omap_verify_speed(struct cpufreq_policy *policy)
 {
+       if (freq_table)
+               return cpufreq_frequency_table_verify(policy, freq_table);
+
        if (policy->cpu)
                return -EINVAL;
 
@@ -70,12 +76,26 @@ static int omap_target(struct cpufreq_policy *policy,
        struct cpufreq_freqs freqs;
        int ret = 0;
 
+       /* Ensure desired rate is within allowed range.  Some govenors
+        * (ondemand) will just pass target_freq=0 to get the minimum. */
+       if (target_freq < policy->cpuinfo.min_freq)
+               target_freq = policy->cpuinfo.min_freq;
+       if (target_freq > policy->cpuinfo.max_freq)
+               target_freq = policy->cpuinfo.max_freq;
+
        freqs.old = omap_getspeed(0);
        freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
        freqs.cpu = 0;
 
+       if (freqs.old == freqs.new)
+               return ret;
+
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       ret = clk_set_rate(mpu_clk, target_freq * 1000);
+#ifdef CONFIG_CPU_FREQ_DEBUG
+       printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
+              freqs.old, freqs.new);
+#endif
+       ret = clk_set_rate(mpu_clk, freqs.new * 1000);
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
        return ret;
@@ -83,16 +103,31 @@ static int omap_target(struct cpufreq_policy *policy,
 
 static int __init omap_cpu_init(struct cpufreq_policy *policy)
 {
+       int result = 0;
+
        mpu_clk = clk_get(NULL, MPU_CLK);
        if (IS_ERR(mpu_clk))
                return PTR_ERR(mpu_clk);
 
        if (policy->cpu != 0)
                return -EINVAL;
+
        policy->cur = policy->min = policy->max = omap_getspeed(0);
-       policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
-       policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+       clk_init_cpufreq_table(&freq_table);
+       if (freq_table) {
+               result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+               if (!result)
+                       cpufreq_frequency_table_get_attr(freq_table,
+                                                       policy->cpu);
+       } else {
+               policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+               policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
+                                                       VERY_HI_RATE) / 1000;
+       }
+
+       /* FIXME: what's the actual transition time? */
+       policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
 
        return 0;
 }
@@ -103,6 +138,11 @@ static int omap_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
+static struct freq_attr *omap_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
 static struct cpufreq_driver omap_driver = {
        .flags          = CPUFREQ_STICKY,
        .verify         = omap_verify_speed,
@@ -111,6 +151,7 @@ static struct cpufreq_driver omap_driver = {
        .init           = omap_cpu_init,
        .exit           = omap_cpu_exit,
        .name           = "omap",
+       .attr           = omap_cpufreq_attr,
 };
 
 static int __init omap_cpufreq_init(void)
@@ -119,3 +160,11 @@ static int __init omap_cpufreq_init(void)
 }
 
 arch_initcall(omap_cpufreq_init);
+
+/*
+ * if ever we want to remove this, upon cleanup call:
+ *
+ * cpufreq_unregister_driver()
+ * cpufreq_frequency_table_put_attr()
+ */
+
index 01da719a745366309dedb2a78ac17216dbbd342b..c22bd5feae310512bdcde62055e8205b379d6c13 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c/menelaus.h>
 
 #include <mach/hardware.h>
-#include <asm/io.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
 
 #include <mach/mmc.h>
 #include <mach/mux.h>
 #include <mach/gpio.h>
-#include <mach/menelaus.h>
+#include <mach/dsp_common.h>
 #include <mach/mcbsp.h>
 
 #if    defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
 
-#include "../plat-omap/dsp/dsp_common.h"
-
 static struct dsp_platform_data dsp_pdata = {
        .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
 };
@@ -76,7 +75,7 @@ int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
 {
        static DEFINE_MUTEX(dsp_pdata_lock);
 
-       mutex_init(&kdev->lock);
+       spin_lock_init(&kdev->lock);
 
        mutex_lock(&dsp_pdata_lock);
        list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
@@ -95,6 +94,10 @@ static inline void omap_init_dsp(void) { }
 
 static void omap_init_kp(void)
 {
+       /* 2430 and 34xx keypad is on TWL4030 */
+       if (cpu_is_omap2430() || cpu_is_omap34xx())
+               return;
+
        if (machine_is_omap_h2() || machine_is_omap_h3()) {
                omap_cfg_reg(F18_1610_KBC0);
                omap_cfg_reg(D20_1610_KBC1);
@@ -156,13 +159,6 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
 {
        int i;
 
-       if (size > OMAP_MAX_MCBSP_COUNT) {
-               printk(KERN_WARNING "Registered too many McBSPs platform_data."
-                       " Using maximum (%d) available.\n",
-                       OMAP_MAX_MCBSP_COUNT);
-               size = OMAP_MAX_MCBSP_COUNT;
-       }
-
        omap_mcbsp_devices = kzalloc(size * sizeof(struct platform_device *),
                                     GFP_KERNEL);
        if (!omap_mcbsp_devices) {
@@ -198,199 +194,45 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
 #if    defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
        defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
-#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
-#define        OMAP_MMC1_BASE          0x4809c000
-#define        OMAP_MMC1_END           (OMAP_MMC1_BASE + 0x1fc)
-#define        OMAP_MMC1_INT           INT_24XX_MMC_IRQ
-
-#define        OMAP_MMC2_BASE          0x480b4000
-#define        OMAP_MMC2_END           (OMAP_MMC2_BASE + 0x1fc)
-#define        OMAP_MMC2_INT           INT_24XX_MMC2_IRQ
-
-#else
-
-#define        OMAP_MMC1_BASE          0xfffb7800
-#define        OMAP_MMC1_END           (OMAP_MMC1_BASE + 0x7f)
-#define OMAP_MMC1_INT          INT_MMC
-
-#define        OMAP_MMC2_BASE          0xfffb7c00      /* omap16xx only */
-#define        OMAP_MMC2_END           (OMAP_MMC2_BASE + 0x7f)
-#define        OMAP_MMC2_INT           INT_1610_MMC2
-
-#endif
-
-static struct omap_mmc_platform_data mmc1_data;
-
-static u64 mmc1_dmamask = 0xffffffff;
-
-static struct resource mmc1_resources[] = {
-       {
-               .start          = OMAP_MMC1_BASE,
-               .end            = OMAP_MMC1_END,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP_MMC1_INT,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mmc_omap_device1 = {
-       .name           = "mmci-omap",
-       .id             = 1,
-       .dev = {
-               .dma_mask       = &mmc1_dmamask,
-               .platform_data  = &mmc1_data,
-       },
-       .num_resources  = ARRAY_SIZE(mmc1_resources),
-       .resource       = mmc1_resources,
-};
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \
-       defined(CONFIG_ARCH_OMAP34XX)
-
-static struct omap_mmc_platform_data mmc2_data;
-
-static u64 mmc2_dmamask = 0xffffffff;
-
-static struct resource mmc2_resources[] = {
-       {
-               .start          = OMAP_MMC2_BASE,
-               .end            = OMAP_MMC2_END,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP_MMC2_INT,
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mmc_omap_device2 = {
-       .name           = "mmci-omap",
-       .id             = 2,
-       .dev = {
-               .dma_mask       = &mmc2_dmamask,
-               .platform_data  = &mmc2_data,
-       },
-       .num_resources  = ARRAY_SIZE(mmc2_resources),
-       .resource       = mmc2_resources,
-};
-#endif
-
-static inline void omap_init_mmc_conf(const struct omap_mmc_config *mmc_conf)
-{
-       if (cpu_is_omap2430() || cpu_is_omap34xx())
-               return;
-
-       if (mmc_conf->mmc[0].enabled) {
-               if (cpu_is_omap24xx()) {
-                       omap_cfg_reg(H18_24XX_MMC_CMD);
-                       omap_cfg_reg(H15_24XX_MMC_CLKI);
-                       omap_cfg_reg(G19_24XX_MMC_CLKO);
-                       omap_cfg_reg(F20_24XX_MMC_DAT0);
-                       omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
-                       omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
-               } else {
-                       omap_cfg_reg(MMC_CMD);
-                       omap_cfg_reg(MMC_CLK);
-                       omap_cfg_reg(MMC_DAT0);
-                       if (cpu_is_omap1710()) {
-                               omap_cfg_reg(M15_1710_MMC_CLKI);
-                               omap_cfg_reg(P19_1710_MMC_CMDDIR);
-                               omap_cfg_reg(P20_1710_MMC_DATDIR0);
-                       }
-               }
-               if (mmc_conf->mmc[0].wire4) {
-                       if (cpu_is_omap24xx()) {
-                               omap_cfg_reg(H14_24XX_MMC_DAT1);
-                               omap_cfg_reg(E19_24XX_MMC_DAT2);
-                               omap_cfg_reg(D19_24XX_MMC_DAT3);
-                               omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
-                               omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
-                               omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
-                       } else {
-                               omap_cfg_reg(MMC_DAT1);
-                               /* NOTE:  DAT2 can be on W10 (here) or M15 */
-                               if (!mmc_conf->mmc[0].nomux)
-                                       omap_cfg_reg(MMC_DAT2);
-                               omap_cfg_reg(MMC_DAT3);
-                       }
-               }
-       }
-
-#ifdef CONFIG_ARCH_OMAP16XX
-       /* block 2 is on newer chips, and has many pinout options */
-       if (mmc_conf->mmc[1].enabled) {
-               if (!mmc_conf->mmc[1].nomux) {
-                       omap_cfg_reg(Y8_1610_MMC2_CMD);
-                       omap_cfg_reg(Y10_1610_MMC2_CLK);
-                       omap_cfg_reg(R18_1610_MMC2_CLKIN);
-                       omap_cfg_reg(W8_1610_MMC2_DAT0);
-                       if (mmc_conf->mmc[1].wire4) {
-                               omap_cfg_reg(V8_1610_MMC2_DAT1);
-                               omap_cfg_reg(W15_1610_MMC2_DAT2);
-                               omap_cfg_reg(R10_1610_MMC2_DAT3);
-                       }
-
-                       /* These are needed for the level shifter */
-                       omap_cfg_reg(V9_1610_MMC2_CMDDIR);
-                       omap_cfg_reg(V5_1610_MMC2_DATDIR0);
-                       omap_cfg_reg(W19_1610_MMC2_DATDIR1);
-               }
+#define OMAP_MMC_NR_RES                2
 
-               /* Feedback clock must be set on OMAP-1710 MMC2 */
-               if (cpu_is_omap1710())
-                       omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
-                                    MOD_CONF_CTRL_1);
-       }
-#endif
-}
-
-static void __init omap_init_mmc(void)
+/*
+ * Register MMC devices. Called from mach-omap1 and mach-omap2 device init.
+ */
+int __init omap_mmc_add(int id, unsigned long base, unsigned long size,
+               unsigned int irq, struct omap_mmc_platform_data *data)
 {
-       const struct omap_mmc_config    *mmc_conf;
-
-       /* NOTE:  assumes MMC was never (wrongly) enabled */
-       mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
-       if (!mmc_conf)
-               return;
-
-       omap_init_mmc_conf(mmc_conf);
-
-       if (mmc_conf->mmc[0].enabled) {
-               mmc1_data.conf = mmc_conf->mmc[0];
-               (void) platform_device_register(&mmc_omap_device1);
-       }
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \
-       defined(CONFIG_ARCH_OMAP34XX)
-       if (mmc_conf->mmc[1].enabled) {
-               mmc2_data.conf = mmc_conf->mmc[1];
-               (void) platform_device_register(&mmc_omap_device2);
-       }
-#endif
-}
+       struct platform_device *pdev;
+       struct resource res[OMAP_MMC_NR_RES];
+       int ret;
+
+       pdev = platform_device_alloc("mmci-omap", id);
+       if (!pdev)
+               return -ENOMEM;
+
+       memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource));
+       res[0].start = base;
+       res[0].end = base + size - 1;
+       res[0].flags = IORESOURCE_MEM;
+       res[1].start = res[1].end = irq;
+       res[1].flags = IORESOURCE_IRQ;
+
+       ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+       if (ret == 0)
+               ret = platform_device_add_data(pdev, data, sizeof(*data));
+       if (ret)
+               goto fail;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto fail;
+       return 0;
 
-void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info)
-{
-       switch (host) {
-       case 1:
-               mmc1_data = *info;
-               break;
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2430) || \
-       defined(CONFIG_ARCH_OMAP34XX)
-       case 2:
-               mmc2_data = *info;
-               break;
-#endif
-       default:
-               BUG();
-       }
+fail:
+       platform_device_put(pdev);
+       return ret;
 }
 
-#else
-static inline void omap_init_mmc(void) {}
-void omap_set_mmc_info(int host, const struct omap_mmc_platform_data *info) {}
 #endif
 
 /*-------------------------------------------------------------------------*/
@@ -441,16 +283,8 @@ static inline void omap_init_uwire(void) {}
 
 #if    defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
 
-#ifdef CONFIG_ARCH_OMAP24XX
-#define        OMAP_WDT_BASE           0x48022000
-#else
-#define        OMAP_WDT_BASE           0xfffeb000
-#endif
-
 static struct resource wdt_resources[] = {
        {
-               .start          = OMAP_WDT_BASE,
-               .end            = OMAP_WDT_BASE + 0x4f,
                .flags          = IORESOURCE_MEM,
        },
 };
@@ -464,6 +298,19 @@ static struct platform_device omap_wdt_device = {
 
 static void omap_init_wdt(void)
 {
+       if (cpu_is_omap16xx())
+               wdt_resources[0].start = 0xfffeb000;
+       else if (cpu_is_omap2420())
+               wdt_resources[0].start = 0x48022000; /* WDT2 */
+       else if (cpu_is_omap2430())
+               wdt_resources[0].start = 0x49016000; /* WDT2 */
+       else if (cpu_is_omap343x())
+               wdt_resources[0].start = 0x48314000; /* WDT2 */
+       else
+               return;
+
+       wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
        (void) platform_device_register(&omap_wdt_device);
 }
 #else
@@ -525,20 +372,14 @@ static inline void omap_init_rng(void) {}
  */
 static int __init omap_init_devices(void)
 {
-/*
- * Need to enable relevant once for 2430 SDP
- */
-#ifndef CONFIG_MACH_OMAP_2430SDP
        /* please keep these calls, and their implementations above,
         * in alphabetical order so they're easier to sort through.
         */
        omap_init_dsp();
        omap_init_kp();
-       omap_init_mmc();
        omap_init_uwire();
        omap_init_wdt();
        omap_init_rng();
-#endif
        return 0;
 }
 arch_initcall(omap_init_devices);
index a63b644ad30574b024f4ff60146f9233b7fa17db..c4e5ba3ef58585c8d323dd7689ba651bcb84e6bc 100644 (file)
@@ -712,6 +712,7 @@ int omap_request_dma(int dev_id, const char *dev_name,
        chan->dev_name = dev_name;
        chan->callback = callback;
        chan->data = data;
+       chan->flags = 0;
 
 #ifndef CONFIG_ARCH_OMAP1
        if (cpu_class_is_omap2()) {
@@ -1233,7 +1234,7 @@ int omap_request_dma_chain(int dev_id, const char *dev_name,
        /* request and reserve DMA channels for the chain */
        for (i = 0; i < no_of_chans; i++) {
                err = omap_request_dma(dev_id, dev_name,
-                                       callback, 0, &channels[i]);
+                                       callback, NULL, &channels[i]);
                if (err < 0) {
                        int j;
                        for (j = 0; j < i; j++)
@@ -1848,9 +1849,22 @@ static int omap2_dma_handle_ch(int ch)
                printk(KERN_INFO
                       "DMA synchronization event drop occurred with device "
                       "%d\n", dma_chan[ch].dev_id);
-       if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ))
+       if (unlikely(status & OMAP2_DMA_TRANS_ERR_IRQ)) {
                printk(KERN_INFO "DMA transaction error with device %d\n",
                       dma_chan[ch].dev_id);
+               if (cpu_class_is_omap2()) {
+                       /* Errata: sDMA Channel is not disabled
+                        * after a transaction error. So we explicitely
+                        * disable the channel
+                        */
+                       u32 ccr;
+
+                       ccr = dma_read(CCR(ch));
+                       ccr &= ~OMAP_DMA_CCR_EN;
+                       dma_write(ccr, CCR(ch));
+                       dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
+               }
+       }
        if (unlikely(status & OMAP2_DMA_SECURE_ERR_IRQ))
                printk(KERN_INFO "DMA secure error with device %d\n",
                       dma_chan[ch].dev_id);
@@ -2297,13 +2311,13 @@ static int __init omap_init_dma(void)
        int ch, r;
 
        if (cpu_class_is_omap1()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP1_DMA_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP1_DMA_BASE);
                dma_lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap24xx()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP24XX_DMA4_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP24XX_DMA4_BASE);
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else if (cpu_is_omap34xx()) {
-               omap_dma_base = (void __iomem *)IO_ADDRESS(OMAP34XX_DMA4_BASE);
+               omap_dma_base = IO_ADDRESS(OMAP34XX_DMA4_BASE);
                dma_lch_count = OMAP_DMA4_LOGICAL_DMA_CH_COUNT;
        } else {
                pr_err("DMA init failed for unsupported omap\n");
index 743a4abcd85d99f6a23bb897be2315b57012fc6f..167ec2fba4a9c83408c0c36ba80da8e700f79b25 100644 (file)
@@ -237,7 +237,7 @@ static struct omap_dm_timer omap3_dm_timers[] = {
        { .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
        { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
        { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
-       { .phys_base = 0x48304000, .irq = INT_24XX_GPTIMER12 },
+       { .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
 };
 
 static const char *omap3_dm_source_names[] __initdata = {
@@ -693,7 +693,7 @@ int __init omap_dm_timer_init(void)
 
        for (i = 0; i < dm_timer_count; i++) {
                timer = &dm_timers[i];
-               timer->io_base = (void __iomem *)io_p2v(timer->phys_base);
+               timer->io_base = IO_ADDRESS(timer->phys_base);
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
                if (cpu_class_is_omap2()) {
                        char clk_name[16];
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..f2dd67a
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ *  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 <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+#include <mach/mux.h>
+#include <mach/board.h>
+#include <mach/gpio-switch.h>
+
+struct gpio_switch {
+       char            name[14];
+       u16             gpio;
+       unsigned        flags:4;
+       unsigned        type:4;
+       unsigned        state:1;
+       unsigned        both_edges:1;
+
+       u16             debounce_rising;
+       u16             debounce_falling;
+
+       void (* notify)(void *data, int state);
+       void *notify_data;
+
+       struct work_struct      work;
+       struct timer_list       timer;
+       struct platform_device  pdev;
+
+       struct list_head        node;
+};
+
+static LIST_HEAD(gpio_switches);
+static struct platform_device *gpio_sw_platform_dev;
+static struct platform_driver gpio_sw_driver;
+
+static const struct omap_gpio_switch *board_gpio_sw_table;
+static int board_gpio_sw_count;
+
+static const char *cover_str[2] = { "open", "closed" };
+static const char *connection_str[2] = { "disconnected", "connected" };
+static const char *activity_str[2] = { "inactive", "active" };
+
+/*
+ * GPIO switch state default debounce delay in ms
+ */
+#define OMAP_GPIO_SW_DEFAULT_DEBOUNCE          10
+
+static const char **get_sw_str(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return cover_str;
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return connection_str;
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return activity_str;
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static const char *get_sw_type(struct gpio_switch *sw)
+{
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+               return "cover";
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+               return "connection";
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               return "activity";
+       default:
+               BUG();
+               return NULL;
+       }
+}
+
+static void print_sw_state(struct gpio_switch *sw, int state)
+{
+       const char **str;
+
+       str = get_sw_str(sw);
+       if (str != NULL)
+               printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]);
+}
+
+static int gpio_sw_get_state(struct gpio_switch *sw)
+{
+       int state;
+
+       state = 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)
+               sw->state = enable = 0;
+       else if (strcmp(state, str[1]) == 0)
+               sw->state = enable = 1;
+       else
+               return -EINVAL;
+
+       if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+               enable = !enable;
+       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), IRQ_TYPE_EDGE_FALLING);
+               else
+                       set_irq_type(OMAP_GPIO_IRQ(sw->gpio), IRQ_TYPE_EDGE_RISING);
+       }
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return IRQ_HANDLED;
+
+       if (state)
+               timeout = sw->debounce_rising;
+       else
+               timeout = sw->debounce_falling;
+       if (!timeout)
+               schedule_work(&sw->work);
+       else
+               mod_timer(&sw->timer, jiffies + msecs_to_jiffies(timeout));
+
+       return IRQ_HANDLED;
+}
+
+static void gpio_sw_timer(unsigned long arg)
+{
+       struct gpio_switch *sw = (struct gpio_switch *) arg;
+
+       schedule_work(&sw->work);
+}
+
+static void gpio_sw_handler(struct work_struct *work)
+{
+       struct gpio_switch *sw = container_of(work, struct gpio_switch, work);
+       int state;
+
+       state = gpio_sw_get_state(sw);
+       if (sw->state == state)
+               return;
+
+       sw->state = state;
+       if (sw->notify != NULL)
+               sw->notify(sw->notify_data, state);
+       sysfs_notify(&sw->pdev.dev.kobj, NULL, "state");
+       print_sw_state(sw, state);
+}
+
+static int __init can_do_both_edges(struct gpio_switch *sw)
+{
+       if (!cpu_class_is_omap1())
+               return 1;
+       if (OMAP_GPIO_IS_MPUIO(sw->gpio))
+               return 0;
+       else
+               return 1;
+}
+
+static void gpio_sw_release(struct device *dev)
+{
+}
+
+static int __init new_switch(struct gpio_switch *sw)
+{
+       int r, direction, trigger;
+
+       switch (sw->type) {
+       case OMAP_GPIO_SWITCH_TYPE_COVER:
+       case OMAP_GPIO_SWITCH_TYPE_CONNECTION:
+       case OMAP_GPIO_SWITCH_TYPE_ACTIVITY:
+               break;
+       default:
+               printk(KERN_ERR "invalid GPIO switch type: %d\n", sw->type);
+               return -EINVAL;
+       }
+
+       sw->pdev.name   = sw->name;
+       sw->pdev.id     = -1;
+
+       sw->pdev.dev.parent = &gpio_sw_platform_dev->dev;
+       sw->pdev.dev.driver = &gpio_sw_driver.driver;
+       sw->pdev.dev.release = gpio_sw_release;
+
+       r = platform_device_register(&sw->pdev);
+       if (r) {
+               printk(KERN_ERR "gpio-switch: platform device registration "
+                      "failed for %s", sw->name);
+               return r;
+       }
+       dev_set_drvdata(&sw->pdev.dev, sw);
+
+       r = omap_request_gpio(sw->gpio);
+       if (r < 0) {
+               platform_device_unregister(&sw->pdev);
+               return r;
+       }
+
+       /* input: 1, output: 0 */
+       direction = !(sw->flags & OMAP_GPIO_SWITCH_FLAG_OUTPUT);
+       omap_set_gpio_direction(sw->gpio, direction);
+
+       sw->state = gpio_sw_get_state(sw);
+
+       r = 0;
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_state);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_type);
+       r |= device_create_file(&sw->pdev.dev, &dev_attr_direction);
+       if (r)
+               printk(KERN_ERR "gpio-switch: attribute file creation "
+                      "failed for %s\n", sw->name);
+
+       if (!direction)
+               return 0;
+
+       if (can_do_both_edges(sw)) {
+               trigger = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
+               sw->both_edges = 1;
+       } else {
+               if (omap_get_gpio_datain(sw->gpio))
+                       trigger = IRQF_TRIGGER_FALLING;
+               else
+                       trigger = IRQF_TRIGGER_RISING;
+       }
+       r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler,
+                       IRQF_SHARED | trigger, sw->name, sw);
+       if (r < 0) {
+               printk(KERN_ERR "gpio-switch: request_irq() failed "
+                      "for GPIO %d\n", sw->gpio);
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               return r;
+       }
+
+       INIT_WORK(&sw->work, gpio_sw_handler);
+       init_timer(&sw->timer);
+
+       sw->timer.function = gpio_sw_timer;
+       sw->timer.data = (unsigned long)sw;
+
+       list_add(&sw->node, &gpio_switches);
+
+       return 0;
+}
+
+static int __init add_atag_switches(void)
+{
+       const struct omap_gpio_switch_config *cfg;
+       struct gpio_switch *sw;
+       int i, r;
+
+       for (i = 0; ; i++) {
+               cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH,
+                                        struct omap_gpio_switch_config, i);
+               if (cfg == NULL)
+                       break;
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strncpy(sw->name, cfg->name, sizeof(cfg->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               sw->debounce_falling = OMAP_GPIO_SW_DEFAULT_DEBOUNCE;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static struct gpio_switch * __init find_switch(int gpio, const char *name)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if ((gpio < 0 || sw->gpio != gpio) &&
+                   (name == NULL || strcmp(sw->name, name) != 0))
+                       continue;
+
+               if (gpio < 0 || name == NULL)
+                       goto no_check;
+
+               if (strcmp(sw->name, name) != 0)
+                       printk("gpio-switch: name mismatch for %d (%s, %s)\n",
+                              gpio, name, sw->name);
+               else if (sw->gpio != gpio)
+                       printk("gpio-switch: GPIO mismatch for %s (%d, %d)\n",
+                              name, gpio, sw->gpio);
+no_check:
+               return sw;
+       }
+       return NULL;
+}
+
+static int __init add_board_switches(void)
+{
+       int i;
+
+       for (i = 0; i < board_gpio_sw_count; i++) {
+               const struct omap_gpio_switch *cfg;
+               struct gpio_switch *sw;
+               int r;
+
+               cfg = board_gpio_sw_table + i;
+               if (strlen(cfg->name) > sizeof(sw->name) - 1)
+                       return -EINVAL;
+               /* Check whether we only update an existing switch
+                * or add a new switch. */
+               sw = find_switch(cfg->gpio, cfg->name);
+               if (sw != NULL) {
+                       sw->debounce_rising = cfg->debounce_rising;
+                       sw->debounce_falling = cfg->debounce_falling;
+                       sw->notify = cfg->notify;
+                       sw->notify_data = cfg->notify_data;
+                       continue;
+               } else {
+                       if (cfg->gpio < 0 || cfg->name == NULL) {
+                               printk("gpio-switch: required switch not "
+                                      "found (%d, %s)\n", cfg->gpio,
+                                      cfg->name);
+                               continue;
+                       }
+               }
+               sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+               if (sw == NULL) {
+                       printk(KERN_ERR "gpio-switch: kmalloc failed\n");
+                       return -ENOMEM;
+               }
+               strlcpy(sw->name, cfg->name, sizeof(sw->name));
+               sw->gpio = cfg->gpio;
+               sw->flags = cfg->flags;
+               sw->type = cfg->type;
+               sw->debounce_rising = cfg->debounce_rising;
+               sw->debounce_falling = cfg->debounce_falling;
+               sw->notify = cfg->notify;
+               sw->notify_data = cfg->notify_data;
+               if ((r = new_switch(sw)) < 0) {
+                       kfree(sw);
+                       return r;
+               }
+       }
+       return 0;
+}
+
+static void gpio_sw_cleanup(void)
+{
+       struct gpio_switch *sw = NULL, *old = NULL;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               if (old != NULL)
+                       kfree(old);
+               flush_scheduled_work();
+               del_timer_sync(&sw->timer);
+
+               free_irq(OMAP_GPIO_IRQ(sw->gpio), sw);
+
+               device_remove_file(&sw->pdev.dev, &dev_attr_state);
+               device_remove_file(&sw->pdev.dev, &dev_attr_type);
+               device_remove_file(&sw->pdev.dev, &dev_attr_direction);
+
+               platform_device_unregister(&sw->pdev);
+               omap_free_gpio(sw->gpio);
+               old = sw;
+       }
+       kfree(old);
+}
+
+static void __init report_initial_state(void)
+{
+       struct gpio_switch *sw;
+
+       list_for_each_entry(sw, &gpio_switches, node) {
+               int state;
+
+               state = omap_get_gpio_datain(sw->gpio);
+               if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED)
+                       state = !state;
+               if (sw->notify != NULL)
+                       sw->notify(sw->notify_data, state);
+               print_sw_state(sw, state);
+       }
+}
+
+static int gpio_sw_remove(struct platform_device *dev)
+{
+       return 0;
+}
+
+static struct platform_driver gpio_sw_driver = {
+       .remove         = gpio_sw_remove,
+       .driver         = {
+               .name   = "gpio-switch",
+       },
+};
+
+void __init omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+                                       int count)
+{
+       BUG_ON(board_gpio_sw_table != NULL);
+
+       board_gpio_sw_table = tbl;
+       board_gpio_sw_count = count;
+}
+
+static int __init gpio_sw_init(void)
+{
+       int r;
+
+       printk(KERN_INFO "OMAP GPIO switch handler initializing\n");
+
+       r = platform_driver_register(&gpio_sw_driver);
+       if (r)
+               return r;
+
+       gpio_sw_platform_dev = platform_device_register_simple("gpio-switch",
+                                                              -1, NULL, 0);
+       if (IS_ERR(gpio_sw_platform_dev)) {
+               r = PTR_ERR(gpio_sw_platform_dev);
+               goto err1;
+       }
+
+       r = add_atag_switches();
+       if (r < 0)
+               goto err2;
+
+       r = add_board_switches();
+       if (r < 0)
+               goto err2;
+
+       report_initial_state();
+
+       return 0;
+err2:
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+err1:
+       platform_driver_unregister(&gpio_sw_driver);
+       return r;
+}
+
+static void __exit gpio_sw_exit(void)
+{
+       gpio_sw_cleanup();
+       platform_device_unregister(gpio_sw_platform_dev);
+       platform_driver_unregister(&gpio_sw_driver);
+}
+
+#ifndef MODULE
+late_initcall(gpio_sw_init);
+#else
+module_init(gpio_sw_init);
+#endif
+module_exit(gpio_sw_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>, Paul Mundt <paul.mundt@nokia.com");
+MODULE_DESCRIPTION("GPIO switch driver");
+MODULE_LICENSE("GPL");
index 9e1341ebc14e8842646ae8a53fb2aa9307031b69..c1346eee678b046ba7869988aceaef7e0065cb6e 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/sysdev.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
 #include <mach/gpio.h>
 #include <asm/mach/irq.h>
 
-#include <asm/io.h>
-
 /*
  * OMAP1510 GPIO registers
  */
-#define OMAP1510_GPIO_BASE             (void __iomem *)0xfffce000
+#define OMAP1510_GPIO_BASE             IO_ADDRESS(0xfffce000)
 #define OMAP1510_GPIO_DATA_INPUT       0x00
 #define OMAP1510_GPIO_DATA_OUTPUT      0x04
 #define OMAP1510_GPIO_DIR_CONTROL      0x08
 /*
  * OMAP1610 specific GPIO registers
  */
-#define OMAP1610_GPIO1_BASE            (void __iomem *)0xfffbe400
-#define OMAP1610_GPIO2_BASE            (void __iomem *)0xfffbec00
-#define OMAP1610_GPIO3_BASE            (void __iomem *)0xfffbb400
-#define OMAP1610_GPIO4_BASE            (void __iomem *)0xfffbbc00
+#define OMAP1610_GPIO1_BASE            IO_ADDRESS(0xfffbe400)
+#define OMAP1610_GPIO2_BASE            IO_ADDRESS(0xfffbec00)
+#define OMAP1610_GPIO3_BASE            IO_ADDRESS(0xfffbb400)
+#define OMAP1610_GPIO4_BASE            IO_ADDRESS(0xfffbbc00)
 #define OMAP1610_GPIO_REVISION         0x0000
 #define OMAP1610_GPIO_SYSCONFIG                0x0010
 #define OMAP1610_GPIO_SYSSTATUS                0x0014
 /*
  * OMAP730 specific GPIO registers
  */
-#define OMAP730_GPIO1_BASE             (void __iomem *)0xfffbc000
-#define OMAP730_GPIO2_BASE             (void __iomem *)0xfffbc800
-#define OMAP730_GPIO3_BASE             (void __iomem *)0xfffbd000
-#define OMAP730_GPIO4_BASE             (void __iomem *)0xfffbd800
-#define OMAP730_GPIO5_BASE             (void __iomem *)0xfffbe000
-#define OMAP730_GPIO6_BASE             (void __iomem *)0xfffbe800
+#define OMAP730_GPIO1_BASE             IO_ADDRESS(0xfffbc000)
+#define OMAP730_GPIO2_BASE             IO_ADDRESS(0xfffbc800)
+#define OMAP730_GPIO3_BASE             IO_ADDRESS(0xfffbd000)
+#define OMAP730_GPIO4_BASE             IO_ADDRESS(0xfffbd800)
+#define OMAP730_GPIO5_BASE             IO_ADDRESS(0xfffbe000)
+#define OMAP730_GPIO6_BASE             IO_ADDRESS(0xfffbe800)
 #define OMAP730_GPIO_DATA_INPUT                0x00
 #define OMAP730_GPIO_DATA_OUTPUT       0x04
 #define OMAP730_GPIO_DIR_CONTROL       0x08
 /*
  * omap24xx specific GPIO registers
  */
-#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 OMAP242X_GPIO1_BASE            IO_ADDRESS(0x48018000)
+#define OMAP242X_GPIO2_BASE            IO_ADDRESS(0x4801a000)
+#define OMAP242X_GPIO3_BASE            IO_ADDRESS(0x4801c000)
+#define OMAP242X_GPIO4_BASE            IO_ADDRESS(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 OMAP243X_GPIO1_BASE            IO_ADDRESS(0x4900C000)
+#define OMAP243X_GPIO2_BASE            IO_ADDRESS(0x4900E000)
+#define OMAP243X_GPIO3_BASE            IO_ADDRESS(0x49010000)
+#define OMAP243X_GPIO4_BASE            IO_ADDRESS(0x49012000)
+#define OMAP243X_GPIO5_BASE            IO_ADDRESS(0x480B6000)
 
 #define OMAP24XX_GPIO_REVISION         0x0000
 #define OMAP24XX_GPIO_SYSCONFIG                0x0010
  * omap34xx specific GPIO registers
  */
 
-#define OMAP34XX_GPIO1_BASE            (void __iomem *)0x48310000
-#define OMAP34XX_GPIO2_BASE            (void __iomem *)0x49050000
-#define OMAP34XX_GPIO3_BASE            (void __iomem *)0x49052000
-#define OMAP34XX_GPIO4_BASE            (void __iomem *)0x49054000
-#define OMAP34XX_GPIO5_BASE            (void __iomem *)0x49056000
-#define OMAP34XX_GPIO6_BASE            (void __iomem *)0x49058000
+#define OMAP34XX_GPIO1_BASE            IO_ADDRESS(0x48310000)
+#define OMAP34XX_GPIO2_BASE            IO_ADDRESS(0x49050000)
+#define OMAP34XX_GPIO3_BASE            IO_ADDRESS(0x49052000)
+#define OMAP34XX_GPIO4_BASE            IO_ADDRESS(0x49054000)
+#define OMAP34XX_GPIO5_BASE            IO_ADDRESS(0x49056000)
+#define OMAP34XX_GPIO6_BASE            IO_ADDRESS(0x49058000)
 
+#define OMAP_MPUIO_VBASE               IO_ADDRESS(OMAP_MPUIO_BASE)
 
 struct gpio_bank {
        void __iomem *base;
@@ -151,6 +151,7 @@ struct gpio_bank {
        u32 level_mask;
        spinlock_t lock;
        struct gpio_chip chip;
+       struct clk *dbck;
 };
 
 #define METHOD_MPUIO           0
@@ -161,7 +162,7 @@ struct gpio_bank {
 
 #ifdef CONFIG_ARCH_OMAP16XX
 static struct gpio_bank gpio_bank_1610[5] = {
-       { OMAP_MPUIO_BASE,     INT_MPUIO,           IH_MPUIO_BASE,     METHOD_MPUIO},
+       { OMAP_MPUIO_VBASE,    INT_MPUIO,           IH_MPUIO_BASE,     METHOD_MPUIO},
        { OMAP1610_GPIO1_BASE, INT_GPIO_BANK1,      IH_GPIO_BASE,      METHOD_GPIO_1610 },
        { OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
        { OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
@@ -171,14 +172,14 @@ static struct gpio_bank gpio_bank_1610[5] = {
 
 #ifdef CONFIG_ARCH_OMAP15XX
 static struct gpio_bank gpio_bank_1510[2] = {
-       { OMAP_MPUIO_BASE,    INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
+       { OMAP_MPUIO_VBASE,   INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
        { OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE,  METHOD_GPIO_1510 }
 };
 #endif
 
 #ifdef CONFIG_ARCH_OMAP730
 static struct gpio_bank gpio_bank_730[7] = {
-       { OMAP_MPUIO_BASE,     INT_730_MPUIO,       IH_MPUIO_BASE,      METHOD_MPUIO },
+       { OMAP_MPUIO_VBASE,    INT_730_MPUIO,       IH_MPUIO_BASE,      METHOD_MPUIO },
        { OMAP730_GPIO1_BASE,  INT_730_GPIO_BANK1,  IH_GPIO_BASE,       METHOD_GPIO_730 },
        { OMAP730_GPIO2_BASE,  INT_730_GPIO_BANK2,  IH_GPIO_BASE + 32,  METHOD_GPIO_730 },
        { OMAP730_GPIO3_BASE,  INT_730_GPIO_BANK3,  IH_GPIO_BASE + 64,  METHOD_GPIO_730 },
@@ -483,10 +484,15 @@ void omap_set_gpio_debounce(int gpio, int enable)
        reg += OMAP24XX_GPIO_DEBOUNCE_EN;
        val = __raw_readl(reg);
 
-       if (enable)
+       if (enable && !(val & l))
                val |= l;
-       else
+       else if (!enable && val & l)
                val &= ~l;
+       else
+               return;
+
+       if (cpu_is_omap34xx())
+               enable ? clk_enable(bank->dbck) : clk_disable(bank->dbck);
 
        __raw_writel(val, reg);
 }
@@ -1281,6 +1287,14 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        spin_unlock_irqrestore(&bank->lock, flags);
 }
 
+static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct gpio_bank *bank;
+
+       bank = container_of(chip, struct gpio_bank, chip);
+       return bank->virtual_irq_start + offset;
+}
+
 /*---------------------------------------------------------------------*/
 
 static int initialized;
@@ -1298,7 +1312,6 @@ static struct clk * gpio5_fck;
 #endif
 
 #if defined(CONFIG_ARCH_OMAP3)
-static struct clk *gpio_fclks[OMAP34XX_NR_GPIOS];
 static struct clk *gpio_iclks[OMAP34XX_NR_GPIOS];
 #endif
 
@@ -1312,9 +1325,7 @@ static int __init _omap_gpio_init(void)
        int i;
        int gpio = 0;
        struct gpio_bank *bank;
-#if defined(CONFIG_ARCH_OMAP3)
        char clk_name[11];
-#endif
 
        initialized = 1;
 
@@ -1369,12 +1380,6 @@ static int __init _omap_gpio_init(void)
                                printk(KERN_ERR "Could not get %s\n", clk_name);
                        else
                                clk_enable(gpio_iclks[i]);
-                       sprintf(clk_name, "gpio%d_fck", i + 1);
-                       gpio_fclks[i] = clk_get(NULL, clk_name);
-                       if (IS_ERR(gpio_fclks[i]))
-                               printk(KERN_ERR "Could not get %s\n", clk_name);
-                       else
-                               clk_enable(gpio_fclks[i]);
                }
        }
 #endif
@@ -1393,7 +1398,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_1610;
-               rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
+               rev = __raw_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
                printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
                       (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1412,7 +1417,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 4;
                gpio_bank = gpio_bank_242x;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1421,7 +1426,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = 5;
                gpio_bank = gpio_bank_243x;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1432,7 +1437,7 @@ static int __init _omap_gpio_init(void)
 
                gpio_bank_count = OMAP34XX_NR_GPIOS;
                gpio_bank = gpio_bank_34xx;
-               rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+               rev = __raw_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
                printk(KERN_INFO "OMAP34xx GPIO hardware version %d.%d\n",
                        (rev >> 4) & 0x0f, rev & 0x0f);
        }
@@ -1441,10 +1446,9 @@ static int __init _omap_gpio_init(void)
                int j, gpio_count = 16;
 
                bank = &gpio_bank[i];
-               bank->base = IO_ADDRESS(bank->base);
                spin_lock_init(&bank->lock);
                if (bank_is_mpuio(bank))
-                       omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
+                       __raw_writew(0xffff, bank->base + OMAP_MPUIO_GPIO_MASKIT);
                if (cpu_is_omap15xx() && bank->method == METHOD_GPIO_1510) {
                        __raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
                        __raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
@@ -1486,6 +1490,7 @@ static int __init _omap_gpio_init(void)
                bank->chip.get = gpio_get;
                bank->chip.direction_output = gpio_output;
                bank->chip.set = gpio_set;
+               bank->chip.to_irq = gpio_2irq;
                if (bank_is_mpuio(bank)) {
                        bank->chip.label = "mpuio";
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -1514,6 +1519,13 @@ static int __init _omap_gpio_init(void)
                }
                set_irq_chained_handler(bank->irq, gpio_irq_handler);
                set_irq_data(bank->irq, bank);
+
+               if (cpu_is_omap34xx()) {
+                       sprintf(clk_name, "gpio%d_dbck", i + 1);
+                       bank->dbck = clk_get(NULL, clk_name);
+                       if (IS_ERR(bank->dbck))
+                               printk(KERN_ERR "Could not get %s\n", clk_name);
+               }
        }
 
        /* Enable system clock for GPIO module.
index 0e6d147ab6f82ed8158a3eec98be3981faa1ddbe..89a6ab0b7db81f21ad32ce1dee89c490bc582838 100644 (file)
@@ -79,26 +79,43 @@ static struct platform_device omap_i2c_devices[] = {
 #endif
 };
 
-static void __init omap_i2c_mux_pins(int bus_id)
+#if defined(CONFIG_ARCH_OMAP24XX)
+static const int omap24xx_pins[][2] = {
+       { M19_24XX_I2C1_SCL, L15_24XX_I2C1_SDA },
+       { J15_24XX_I2C2_SCL, H19_24XX_I2C2_SDA },
+};
+#else
+static const int omap24xx_pins[][2] = {};
+#endif
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const int omap34xx_pins[][2] = {
+       { K21_34XX_I2C1_SCL, J21_34XX_I2C1_SDA},
+       { AF15_34XX_I2C2_SCL, AE15_34XX_I2C2_SDA},
+       { AF14_34XX_I2C3_SCL, AG14_34XX_I2C3_SDA},
+};
+#else
+static const int omap34xx_pins[][2] = {};
+#endif
+
+static void __init omap_i2c_mux_pins(int bus)
 {
-       /* TODO: Muxing for OMAP3 */
-       switch (bus_id) {
-       case 1:
-               if (cpu_class_is_omap1()) {
-                       omap_cfg_reg(I2C_SCL);
-                       omap_cfg_reg(I2C_SDA);
-               } else if (cpu_is_omap24xx()) {
-                       omap_cfg_reg(M19_24XX_I2C1_SCL);
-                       omap_cfg_reg(L15_24XX_I2C1_SDA);
-               }
-               break;
-       case 2:
-               if (cpu_is_omap24xx()) {
-                       omap_cfg_reg(J15_24XX_I2C2_SCL);
-                       omap_cfg_reg(H19_24XX_I2C2_SDA);
-               }
-               break;
+       int scl, sda;
+
+       if (cpu_class_is_omap1()) {
+               scl = I2C_SCL;
+               sda = I2C_SDA;
+       } else if (cpu_is_omap24xx()) {
+               scl = omap24xx_pins[bus][0];
+               sda = omap24xx_pins[bus][1];
+       } else if (cpu_is_omap34xx()) {
+               scl = omap34xx_pins[bus][0];
+               sda = omap34xx_pins[bus][1];
+       } else {
+               return;
        }
+
+       omap_cfg_reg(sda);
+       omap_cfg_reg(scl);
 }
 
 int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
@@ -142,6 +159,6 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
                res[1].start = irq;
        }
 
-       omap_i2c_mux_pins(bus_id);
+       omap_i2c_mux_pins(bus_id - 1);
        return platform_device_register(pdev);
 }
index 5ccedac775268aa4b197a1ce1e9394a4a8db7816..188fe8b1308892feb5c4c82c5eef49ead206c7da 100644 (file)
 #define TLV320AIC23ID1                  (0x1a) // cs low
 #define TLV320AIC23ID2                  (0x1b) // cs high
 
-void aic23_power_up(void);
-void aic23_power_down(void);
+#ifdef CONFIG_SENSORS_TLV320AIC23
+extern void aic23_power_up(void);
+extern void aic23_power_down(void);
+#else
+static inline void aic23_power_up(void)
+{
+}
+
+static inline void aic23_power_down(void)
+{
+}
+#endif
 
 #endif /* __ASM_ARCH_AIC23_H */
index cf1dc02239495a8a1f2762d4eba8290c01f4d856..10d449ea7ed0d728106117d9c9ee64cd3580c875 100644 (file)
 #define __ASM_ARCH_OMAP_2430SDP_H
 
 /* Placeholder for 2430SDP specific defines */
-#define OMAP24XX_ETHR_START             0x08000300
+#define OMAP24XX_ETHR_START            0x08000300
 #define OMAP24XX_ETHR_GPIO_IRQ         149
 #define SDP2430_CS0_BASE               0x04000000
 
-#define TWL4030_IRQNUM                 INT_24XX_SYS_NIRQ
+/* Function prototypes */
+extern void sdp2430_flash_init(void);
+extern void sdp2430_usb_init(void);
 
 #endif /* __ASM_ARCH_OMAP_2430SDP_H */
diff --git a/arch/arm/plat-omap/include/mach/board-3430sdp.h b/arch/arm/plat-omap/include/mach/board-3430sdp.h
new file mode 100644 (file)
index 0000000..67d3f78
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-3430sdp.h
+ *
+ * Hardware definitions for TI OMAP3430 SDP board.
+ *
+ * Initial creation by Syed Mohammed Khasim
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_3430SDP_H
+#define __ASM_ARCH_OMAP_3430SDP_H
+
+extern void sdp3430_usb_init(void);
+extern void sdp3430_flash_init(void);
+extern void twl4030_bci_battery_init(void);
+
+#define DEBUG_BASE                     0x08000000  /* debug board */
+
+/* Placeholder for 3430SDP specific defines */
+
+#define OMAP34XX_ETHR_START            DEBUG_BASE
+#define OMAP34XX_ETHR_GPIO_IRQ_SDPV1   29
+#define OMAP34XX_ETHR_GPIO_IRQ_SDPV2   6
+
+/*
+ * GPIO used for TSC2046, TI's Touchscreen controller
+ */
+#define OMAP34XX_TS_GPIO_IRQ_SDPV1     3
+#define OMAP34XX_TS_GPIO_IRQ_SDPV2     2
+
+/* NAND */
+/* IMPORTANT NOTE ON MAPPING
+ * 3430SDP - 34XX
+ * ----------
+ * NOR always on 0x04000000 for SDPV1
+ * NOR always on 0x10000000 for SDPV2
+ * MPDB always on 0x08000000
+ * NAND always on 0x0C000000
+ * OneNand Mapped to 0x20000000
+ * Boot Mode(NAND/NOR). The other on CS1
+ */
+#define FLASH_BASE_SDPV1       0x04000000 /* NOR flash (64 Meg aligned) */
+#define FLASH_BASE_SDPV2       0x10000000 /* NOR flash (256 Meg aligned) */
+#define DEBUG_BASE             0x08000000 /* debug board */
+#define NAND_BASE              0x0C000000 /* NAND flash */
+#define ONENAND_MAP            0x20000000 /* OneNand flash */
+
+/* various memory sizes */
+#define FLASH_SIZE_SDPV1       SZ_64M
+#define FLASH_SIZE_SDPV2       SZ_128M
+
+#endif /* __ASM_ARCH_OMAP_3430SDP_H */
+
index d6f2a8e963d5c86340bec27d604217699341de04..731c858cf3fe70e836a9fbead02bee5ed7bfb5fa 100644 (file)
 
 extern void apollon_mmc_init(void);
 
+static inline int apollon_plus(void)
+{
+       /* The apollon plus has IDCODE revision 5 */
+       return system_rev & 0xc0;
+}
+
 /* Placeholder for APOLLON specific defines */
 #define APOLLON_ETHR_GPIO_IRQ          74
 
index 2a050e9be65f9089612eaadef6446831e891b293..15531c8dc0e63bf3110503da7b43905f723bf29f 100644 (file)
 #ifndef __ASM_ARCH_OMAP_H2_H
 #define __ASM_ARCH_OMAP_H2_H
 
-/* Placeholder for H2 specific defines */
-
 /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
 #define OMAP1610_ETHR_START            0x04000300
 
+#define H2_TPS_GPIO_BASE               (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */)
+#      define H2_TPS_GPIO_MMC_PWR_EN   (H2_TPS_GPIO_BASE + 3)
+
 extern void h2_mmc_init(void);
-extern void h2_mmc_slot_cover_handler(void *arg, int state);
 
 #endif /*  __ASM_ARCH_OMAP_H2_H */
 
index 14909dc7858a397d23c23be0e3b5bec1aec02e61..1888326da7ea325805f4052a8230439ecf1b235e 100644 (file)
@@ -30,7 +30,9 @@
 /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
 #define OMAP1710_ETHR_START            0x04000300
 
+#define H3_TPS_GPIO_BASE               (OMAP_MAX_GPIO_LINES + 16 /* MPUIO */)
+#      define H3_TPS_GPIO_MMC_PWR_EN   (H3_TPS_GPIO_BASE + 4)
+
 extern void h3_mmc_init(void);
-extern void h3_mmc_slot_cover_handler(void *arg, int state);
 
 #endif /*  __ASM_ARCH_OMAP_H3_H */
index 1470cd3e519b80d746388cb0414b0fa59f596d43..7c3fa0f0a65e1512b2efe9e55debfe199d87a789 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/plat-omap/include/mach/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>
  *
@@ -29,6 +29,9 @@
 #ifndef __ASM_ARCH_OMAP_H4_H
 #define __ASM_ARCH_OMAP_H4_H
 
+/* MMC Prototypes */
+extern void h4_mmc_init(void);
+
 /* Placeholder for H4 specific defines */
 #define OMAP24XX_ETHR_GPIO_IRQ         92
 #endif /*  __ASM_ARCH_OMAP_H4_H */
diff --git a/arch/arm/plat-omap/include/mach/board-ldp.h b/arch/arm/plat-omap/include/mach/board-ldp.h
new file mode 100644 (file)
index 0000000..66e2746
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-ldp.h
+ *
+ * Hardware definitions for TI OMAP3 LDP.
+ *
+ * Copyright (C) 2008 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS 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_LDP_H
+#define __ASM_ARCH_OMAP_LDP_H
+
+extern void twl4030_bci_battery_init(void);
+
+#define TWL4030_IRQNUM         INT_34XX_SYS_NIRQ
+
+#endif /* __ASM_ARCH_OMAP_LDP_H */
index 2abbe001af8c43535a97624cd5a309d1cf4cc2fc..198d761136b5e3e4003acf1909261ca0fe5a1e9a 100644 (file)
@@ -6,17 +6,30 @@
  *  Copyright (C) 2005 Nokia Corporation
  */
 
-#ifndef _OMAP_BOARD_NOKIA_H
-#define _OMAP_BOARD_NOKIA_H
+#ifndef __ASM_ARCH_OMAP_NOKIA_H
+#define __ASM_ARCH_OMAP_NOKIA_H
 
 #include <linux/types.h>
 
+struct tsc2301_platform_data;
+struct dsp_kfunc_device;
+extern void n800_bt_init(void);
+extern void n800_dsp_init(void);
+extern void n800_flash_init(void);
+extern void n800_mmc_init(void);
+extern void n800_pm_init(void);
+extern void n800_usb_init(void);
+extern void n800_cam_init(void);
+extern void n800_audio_init(struct tsc2301_platform_data *);
+extern int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage);
+extern int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage);
+extern void n800_mmc_slot1_cover_handler(void *arg, int state);
+
 #define OMAP_TAG_NOKIA_BT      0x4e01
 #define OMAP_TAG_WLAN_CX3110X  0x4e02
 #define OMAP_TAG_CBUS          0x4e03
 #define OMAP_TAG_EM_ASIC_BB5   0x4e04
 
-
 #define BT_CHIP_CSR            1
 #define BT_CHIP_TI             2
 
diff --git a/arch/arm/plat-omap/include/mach/board-omap2evm.h b/arch/arm/plat-omap/include/mach/board-omap2evm.h
new file mode 100644 (file)
index 0000000..ec548d4
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-omap2evm.h
+ *
+ * Hardware definitions for Mistral's OMAP2EVM board.
+ *
+ * Based on board-2430sdp.h
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP2_EVM_H
+#define __ASM_ARCH_OMAP2_EVM_H
+
+/* Placeholder for OMAP2EVM specific defines */
+#define OMAP2EVM_ETHR_START                    0x2c000000
+#define OMAP2EVM_ETHR_SIZE                     1024
+#define OMAP2EVM_ETHR_GPIO_IRQ         149
+
+#endif /* __ASM_ARCH_OMAP2_EVM_H */
diff --git a/arch/arm/plat-omap/include/mach/board-omap3beagle.h b/arch/arm/plat-omap/include/mach/board-omap3beagle.h
new file mode 100644 (file)
index 0000000..3080d52
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-omap3beagle.h
+ *
+ * Hardware definitions for TI OMAP3 BEAGLE.
+ *
+ * Initial creation by Syed Mohammed Khasim <khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP3_BEAGLE_H
+#define __ASM_ARCH_OMAP3_BEAGLE_H
+
+#endif /* __ASM_ARCH_OMAP3_BEAGLE_H */
+
diff --git a/arch/arm/plat-omap/include/mach/board-omap3evm.h b/arch/arm/plat-omap/include/mach/board-omap3evm.h
new file mode 100644 (file)
index 0000000..7a540e9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/arm/plat-omap/include/mach/board-omap3evm.h
+ *
+ * Hardware definitions for TI OMAP3 EVM.
+ *
+ * Initial creation by Syed Mohammed Khasim <khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP3_EVM_H
+#define __ASM_ARCH_OMAP3_EVM_H
+
+extern void omap3evm_flash_init(void);
+
+#define OMAP3_EVM_TS_GPIO      175
+
+#define ONENAND_MAP            0x20000000
+
+#define OMAP3EVM_ETHR_START    0x2c000000
+#define OMAP3EVM_ETHR_SIZE     1024
+#define OMAP3EVM_ETHR_GPIO_IRQ 176
+#define OMAP3EVM_SMC911X_CS    5
+
+#endif /* __ASM_ARCH_OMAP3_EVM_H */
+
diff --git a/arch/arm/plat-omap/include/mach/board-overo.h b/arch/arm/plat-omap/include/mach/board-overo.h
new file mode 100644 (file)
index 0000000..7ecae66
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * board-overo.h (Gumstix Overo)
+ *
+ * Initial code: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You 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_OVERO_H
+#define __ASM_ARCH_OVERO_H
+
+#define OVERO_GPIO_BT_XGATE    15
+#define OVERO_GPIO_W2W_NRESET  16
+#define OVERO_GPIO_BT_NRESET   164
+#define OVERO_GPIO_USBH_CPEN   168
+#define OVERO_GPIO_USBH_NRESET 183
+
+#endif /* ____ASM_ARCH_OVERO_H */
+
index 54445642f35d4ff4fd54e137fdcf845acdfb9238..2ba5e5dffadedeb125286490e7c3465bf34e2516 100644 (file)
@@ -16,7 +16,6 @@
 
 /* Different peripheral ids */
 #define OMAP_TAG_CLOCK         0x4f01
-#define OMAP_TAG_MMC           0x4f02
 #define OMAP_TAG_SERIAL_CONSOLE 0x4f03
 #define OMAP_TAG_USB           0x4f04
 #define OMAP_TAG_LCD           0x4f05
 #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 {
@@ -35,25 +37,6 @@ struct omap_clock_config {
        u8 system_clock_type;
 };
 
-struct omap_mmc_conf {
-       unsigned enabled:1;
-       /* nomux means "standard" muxing is wrong on this board, and that
-        * board-specific code handled it before common init logic.
-        */
-       unsigned nomux:1;
-       /* switch pin can be for card detect (default) or card cover */
-       unsigned cover:1;
-       /* 4 wire signaling is optional, and is only used for SD/SDIO */
-       unsigned wire4:1;
-       s16 power_pin;
-       s16 switch_pin;
-       s16 wp_pin;
-};
-
-struct omap_mmc_config {
-       struct omap_mmc_conf mmc[2];
-};
-
 struct omap_serial_console_config {
        u8 console_uart;
        u32 console_speed;
@@ -64,12 +47,6 @@ struct omap_sti_console_config {
        u8 channel;
 };
 
-struct omap_camera_sensor_config {
-       u16 reset_gpio;
-       int (*power_on)(void * data);
-       int (*power_off)(void * data);
-};
-
 struct omap_usb_config {
        /* Configure drivers according to the connectors on your board:
         *  - "A" connector (rectagular)
@@ -125,13 +102,13 @@ struct omap_pwm_led_platform_data {
        void (*set_power)(struct omap_pwm_led_platform_data *self, int on_off);
 };
 
-/* See arch/arm/plat-omap/include/mach/gpio-switch.h for definitions */
+/* See include/asm-arm/arch-omap/gpio-switch.h for definitions */
 struct omap_gpio_switch_config {
        char name[12];
        u16 gpio;
-       int flags:4;
-       int type:4;
-       int key_code:24; /* Linux key code */
+       u8 flags:4;
+       u8 type:4;
+       unsigned int key_code:24; /* Linux key code */
 };
 
 struct omap_uart_config {
@@ -139,8 +116,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];
 };
 
@@ -153,9 +147,6 @@ struct omap_version_config {
        char version[12];
 };
 
-
-#include <mach/board-nokia.h>
-
 struct omap_board_config_entry {
        u16 tag;
        u16 len;
index 92f7c7238fcd9b94d019287dc1ea7ddd07fca472..9088925877364dc8f488b4b44d16d0c70dd01aba 100644 (file)
@@ -15,6 +15,7 @@
 
 struct module;
 struct clk;
+struct clockdomain;
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 
@@ -30,7 +31,7 @@ struct clksel {
 };
 
 struct dpll_data {
-       void __iomem            *mult_div1_reg;
+       u16                     mult_div1_reg;
        u32                     mult_mask;
        u32                     div1_mask;
        u16                     last_rounded_m;
@@ -40,17 +41,19 @@ struct dpll_data {
        u16                     max_multiplier;
        u8                      max_divider;
        u32                     max_tolerance;
+       u16                     idlest_reg;
+       u32                     idlest_mask;
+       struct clk              *bypass_clk;
 #  if defined(CONFIG_ARCH_OMAP3)
+       u32                     freqsel_mask;
        u8                      modes;
-       void __iomem            *control_reg;
+       u16                     control_reg;
        u32                     enable_mask;
        u8                      auto_recal_bit;
        u8                      recal_en_bit;
        u8                      recal_st_bit;
-       void __iomem            *autoidle_reg;
+       u16                     autoidle_reg;
        u32                     autoidle_mask;
-       void __iomem            *idlest_reg;
-       u8                      idlest_bit;
 #  endif
 };
 
@@ -64,9 +67,10 @@ struct clk {
        struct clk              *parent;
        unsigned long           rate;
        __u32                   flags;
-       void __iomem            *enable_reg;
+       u32                     enable_reg;
        __u8                    enable_bit;
        __s8                    usecount;
+       u8                      idlest_bit;
        void                    (*recalc)(struct clk *);
        int                     (*set_rate)(struct clk *, unsigned long);
        long                    (*round_rate)(struct clk *, unsigned long);
@@ -75,10 +79,15 @@ struct clk {
        void                    (*disable)(struct clk *);
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
        u8                      fixed_div;
-       void __iomem            *clksel_reg;
+       u16                     clksel_reg;
        u32                     clksel_mask;
        const struct clksel     *clksel;
        struct dpll_data        *dpll_data;
+       union {
+               const char              *name;
+               struct clockdomain      *ptr;
+       } clkdm;
+       s16                     prcm_mod;
 #else
        __u8                    rate_offset;
        __u8                    src_offset;
@@ -107,16 +116,19 @@ struct clk_functions {
 
 extern unsigned int mpurate;
 
-extern int clk_init(struct clk_functions * custom_clocks);
+extern int clk_init(struct clk_functions *custom_clocks);
 extern int clk_register(struct clk *clk);
 extern void clk_unregister(struct clk *clk);
 extern void propagate_rate(struct clk *clk);
 extern void recalculate_root_clocks(void);
-extern void followparent_recalc(struct clk * clk);
+extern void followparent_recalc(struct clk *clk);
 extern void clk_allow_idle(struct clk *clk);
 extern void clk_deny_idle(struct clk *clk);
 extern int clk_get_usecount(struct clk *clk);
 extern void clk_enable_init_clocks(void);
+#ifdef CONFIG_CPU_FREQ
+extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
+#endif
 
 /* Clock flags */
 #define RATE_CKCTL             (1 << 0)        /* Main fixed ratio clocks */
@@ -125,14 +137,15 @@ extern void clk_enable_init_clocks(void);
 #define VIRTUAL_CLOCK          (1 << 3)        /* Composite clock from table */
 #define ALWAYS_ENABLED         (1 << 4)        /* Clock cannot be disabled */
 #define ENABLE_REG_32BIT       (1 << 5)        /* Use 32-bit access */
-#define VIRTUAL_IO_ADDRESS     (1 << 6)        /* Clock in virtual address */
+
 #define CLOCK_IDLE_CONTROL     (1 << 7)
 #define CLOCK_NO_IDLE_PARENT   (1 << 8)
 #define DELAYED_APP            (1 << 9)        /* Delay application of clock */
 #define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
 #define ENABLE_ON_INIT         (1 << 11)       /* Enable upon framework init */
-#define INVERT_ENABLE           (1 << 12)       /* 0 enables, 1 disables */
-/* bits 13-20 are currently free */
+#define INVERT_ENABLE          (1 << 12)       /* 0 enables, 1 disables */
+#define WAIT_READY             (1 << 13)       /* wait for dev to leave idle */
+/* bits 14-20 are currently free */
 #define CLOCK_IN_OMAP310       (1 << 21)
 #define CLOCK_IN_OMAP730       (1 << 22)
 #define CLOCK_IN_OMAP1510      (1 << 23)
@@ -142,17 +155,24 @@ extern void clk_enable_init_clocks(void);
 #define CLOCK_IN_OMAP343X      (1 << 27)       /* clocks common to all 343X */
 #define PARENT_CONTROLS_CLOCK  (1 << 28)
 #define CLOCK_IN_OMAP3430ES1   (1 << 29)       /* 3430ES1 clocks only */
-#define CLOCK_IN_OMAP3430ES2   (1 << 30)       /* 3430ES2 clocks only */
+#define CLOCK_IN_OMAP3430ES2   (1 << 30)       /* 3430ES2+ clocks only */
 
 /* Clksel_rate flags */
 #define DEFAULT_RATE           (1 << 0)
 #define RATE_IN_242X           (1 << 1)
 #define RATE_IN_243X           (1 << 2)
 #define RATE_IN_343X           (1 << 3)        /* rates common to all 343X */
-#define RATE_IN_3430ES2                (1 << 4)        /* 3430ES2 rates only */
+#define RATE_IN_3430ES2                (1 << 4)        /* 3430ES2+ rates only */
 
 #define RATE_IN_24XX           (RATE_IN_242X | RATE_IN_243X)
 
+/*
+ * clk.prcm_mod flags (possible since only the top byte in clk.prcm_mod
+ * is significant)
+ */
+#define PRCM_MOD_ADDR_MASK     0xff00
+#define CLK_REG_IN_PRM         (1 << 0)
+#define CLK_REG_IN_SCM         (1 << 1)
 
 /* CM_CLKSEL2_PLL.CORE_CLK_SRC options (24XX) */
 #define CORE_CLK_SRC_32K               0
diff --git a/arch/arm/plat-omap/include/mach/clockdomain.h b/arch/arm/plat-omap/include/mach/clockdomain.h
new file mode 100644 (file)
index 0000000..b9d0dd2
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/plat-omap/include/mach/clockdomain.h
+ *
+ * OMAP2/3 clockdomain framework functions
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+#define __ASM_ARM_ARCH_OMAP_CLOCKDOMAIN_H
+
+#include <mach/powerdomain.h>
+#include <mach/clock.h>
+#include <mach/cpu.h>
+
+/* Clockdomain capability flags */
+#define CLKDM_CAN_FORCE_SLEEP                  (1 << 0)
+#define CLKDM_CAN_FORCE_WAKEUP                 (1 << 1)
+#define CLKDM_CAN_ENABLE_AUTO                  (1 << 2)
+#define CLKDM_CAN_DISABLE_AUTO                 (1 << 3)
+
+#define CLKDM_CAN_HWSUP                (CLKDM_CAN_ENABLE_AUTO | CLKDM_CAN_DISABLE_AUTO)
+#define CLKDM_CAN_SWSUP                (CLKDM_CAN_FORCE_SLEEP | CLKDM_CAN_FORCE_WAKEUP)
+#define CLKDM_CAN_HWSUP_SWSUP  (CLKDM_CAN_SWSUP | CLKDM_CAN_HWSUP)
+
+/* OMAP24XX CM_CLKSTCTRL_*.AUTOSTATE_* register bit values */
+#define OMAP24XX_CLKSTCTRL_DISABLE_AUTO                0x0
+#define OMAP24XX_CLKSTCTRL_ENABLE_AUTO         0x1
+
+/* OMAP3XXX CM_CLKSTCTRL_*.CLKTRCTRL_* register bit values */
+#define OMAP34XX_CLKSTCTRL_DISABLE_AUTO                0x0
+#define OMAP34XX_CLKSTCTRL_FORCE_SLEEP         0x1
+#define OMAP34XX_CLKSTCTRL_FORCE_WAKEUP                0x2
+#define OMAP34XX_CLKSTCTRL_ENABLE_AUTO         0x3
+
+/*
+ * struct clkdm_pwrdm_autodep - a powerdomain that should have wkdeps
+ * and sleepdeps added when a powerdomain should stay active in hwsup mode;
+ * and conversely, removed when the powerdomain should be allowed to go
+ * inactive in hwsup mode.
+ */
+struct clkdm_pwrdm_autodep {
+
+       union {
+               /* Name of the powerdomain to add a wkdep/sleepdep on */
+               const char *name;
+
+               /* Powerdomain pointer (looked up at clkdm_init() time) */
+               struct powerdomain *ptr;
+       } pwrdm;
+
+       /* OMAP chip types that this clockdomain dep is valid on */
+       const struct omap_chip_id omap_chip;
+
+};
+
+struct clockdomain {
+
+       /* Clockdomain name */
+       const char *name;
+
+       union {
+               /* Powerdomain enclosing this clockdomain */
+               const char *name;
+
+               /* Powerdomain pointer assigned at clkdm_register() */
+               struct powerdomain *ptr;
+       } pwrdm;
+
+       /* CLKTRCTRL/AUTOSTATE field mask in CM_CLKSTCTRL reg */
+       const u16 clktrctrl_mask;
+
+       /* Clockdomain capability flags */
+       const u8 flags;
+
+       /* OMAP chip types that this clockdomain is valid on */
+       const struct omap_chip_id omap_chip;
+
+       /* Usecount tracking */
+       atomic_t usecount;
+
+       struct list_head node;
+
+};
+
+void clkdm_init(struct clockdomain **clkdms, struct clkdm_pwrdm_autodep *autodeps);
+int clkdm_register(struct clockdomain *clkdm);
+int clkdm_unregister(struct clockdomain *clkdm);
+struct clockdomain *clkdm_lookup(const char *name);
+
+int clkdm_for_each(int (*fn)(struct clockdomain *clkdm));
+struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm);
+
+void omap2_clkdm_allow_idle(struct clockdomain *clkdm);
+void omap2_clkdm_deny_idle(struct clockdomain *clkdm);
+
+int omap2_clkdm_wakeup(struct clockdomain *clkdm);
+int omap2_clkdm_sleep(struct clockdomain *clkdm);
+
+int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
+int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk);
+
+#endif
index 06093112b665c6b2b77330647f11938cfe898825..5f4624939e626756587f65546c476582d36a0505 100644 (file)
@@ -34,6 +34,7 @@ struct sys_timer;
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 extern void omap_serial_init(void);
+extern void omap_serial_enable_clocks(int enable);
 #ifdef CONFIG_I2C_OMAP
 extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
                                 struct i2c_board_info const *info,
@@ -49,6 +50,7 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
 
 /* IO bases for various OMAP processors */
 struct omap_globals {
+       u32             class;          /* OMAP class to detect */
        void __iomem    *tap;           /* Control module ID code */
        void __iomem    *sdrc;          /* SDRAM Controller */
        void __iomem    *sms;           /* SDRAM Memory Scheduler */
@@ -62,8 +64,14 @@ void omap2_set_globals_243x(void);
 void omap2_set_globals_343x(void);
 
 /* These get called from omap2_set_globals_xxxx(), do not call these */
-void omap2_set_globals_memory(struct omap_globals *);
+void omap2_set_globals_tap(struct omap_globals *);
+void omap2_set_globals_sdrc(struct omap_globals *);
 void omap2_set_globals_control(struct omap_globals *);
 void omap2_set_globals_prcm(struct omap_globals *);
+#ifdef CONFIG_ARCH_OMAP24XX
+void omap2_set_globals_clock24xx(struct omap_globals *);
+#else
+#define omap2_set_globals_clock24xx(x) do { } while (0)
+#endif
 
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
index e3fd62d9a995115bc2514807a8203f52dfe31684..9ca0e08a2470123248694d83ac11d3bc86b78165 100644 (file)
@@ -1,13 +1,10 @@
-#ifndef __ASM_ARCH_CONTROL_H
-#define __ASM_ARCH_CONTROL_H
-
 /*
- * arch/arm/plat-omap/include/mach/control.h
+ * include/asm-arm/arch-omap/control.h
  *
  * OMAP2/3 System Control Module definitions
  *
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
  *
  * Written by Paul Walmsley
  *
  * the Free Software Foundation.
  */
 
+#ifndef __ASM_ARCH_CONTROL_H
+#define __ASM_ARCH_CONTROL_H
+
 #include <mach/io.h>
 
+#ifndef __ASSEMBLY__
 #define OMAP242X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
 #define OMAP243X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
 #define OMAP343X_CTRL_REGADDR(reg)                                     \
-       (void __iomem *)IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+       IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#else
+#define OMAP242X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP242X_CTRL_BASE + (reg))
+#define OMAP243X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP243X_CTRL_BASE + (reg))
+#define OMAP343X_CTRL_REGADDR(reg)     IO_ADDRESS(OMAP343X_CTRL_BASE + (reg))
+#endif /* __ASSEMBLY__ */
 
 /*
  * As elsewhere, the "OMAP2_" prefix indicates that the macro is valid for
 #define OMAP343X_CONTROL_TEST_KEY_11   (OMAP2_CONTROL_GENERAL + 0x00f4)
 #define OMAP343X_CONTROL_TEST_KEY_12   (OMAP2_CONTROL_GENERAL + 0x00f8)
 #define OMAP343X_CONTROL_TEST_KEY_13   (OMAP2_CONTROL_GENERAL + 0x00fc)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD1        (OMAP2_CONTROL_GENERAL + 0x0110)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD1        (OMAP2_CONTROL_GENERAL + 0x0114)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD1        (OMAP2_CONTROL_GENERAL + 0x0118)
+#define OMAP343X_CONTROL_FUSE_OPP4_VDD1        (OMAP2_CONTROL_GENERAL + 0x011c)
+#define OMAP343X_CONTROL_FUSE_OPP5_VDD1        (OMAP2_CONTROL_GENERAL + 0x0120)
+#define OMAP343X_CONTROL_FUSE_OPP1_VDD2        (OMAP2_CONTROL_GENERAL + 0x0124)
+#define OMAP343X_CONTROL_FUSE_OPP2_VDD2        (OMAP2_CONTROL_GENERAL + 0x0128)
+#define OMAP343X_CONTROL_FUSE_OPP3_VDD2        (OMAP2_CONTROL_GENERAL + 0x012c)
+#define OMAP343X_CONTROL_FUSE_SR       (OMAP2_CONTROL_GENERAL + 0x0130)
 #define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
 #define OMAP343X_CONTROL_IVA2_BOOTMOD  (OMAP2_CONTROL_GENERAL + 0x0194)
+#define OMAP343X_CONTROL_TEMP_SENSOR   (OMAP2_CONTROL_GENERAL + 0x02b4)
 
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
 #define OMAP2_SYSBOOT_1_MASK           (1 << 1)
 #define OMAP2_SYSBOOT_0_MASK           (1 << 0)
 
+/* CONTROL_FUSE_SR bits */
+#define OMAP343X_SR2_SENNENABLE_MASK   (0x3 << 10)
+#define OMAP343X_SR2_SENNENABLE_SHIFT  10
+#define OMAP343X_SR2_SENPENABLE_MASK   (0x3 << 8)
+#define OMAP343X_SR2_SENPENABLE_SHIFT  8
+#define OMAP343X_SR1_SENNENABLE_MASK   (0x3 << 2)
+#define OMAP343X_SR1_SENNENABLE_SHIFT  2
+#define OMAP343X_SR1_SENPENABLE_MASK   (0x3 << 0)
+#define OMAP343X_SR1_SENPENABLE_SHIFT  0
+
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 extern void __iomem *omap_ctrl_base_get(void);
index 05aee0eda34fb9de569e630bc966e59c4f1a8928..4325bbc9747776fc25177e372a15f06daf85739c 100644 (file)
 
 struct omap_chip_id {
        u8 oc;
+       u8 type;
 };
 
 #define OMAP_CHIP_INIT(x)      { .oc = x }
 
+/*
+ * system_rev bits:
+ * CPU id bits (0730, 1510, 1710, 2422...)     [31:16]
+ * CPU revision        (See _REV_ defined in cpu.h)    [15:08]
+ * CPU class bits (15xx, 16xx, 24xx, 34xx...)  [07:00]
+ */
 extern unsigned int system_rev;
 
-#define omap2_cpu_rev()                ((system_rev >> 12) & 0x0f)
-
 /*
  * Test if multicore OMAP support is needed
  */
@@ -108,7 +113,7 @@ extern unsigned int system_rev;
  * cpu_is_omap243x():  True for OMAP2430
  * cpu_is_omap343x():  True for OMAP3430
  */
-#define GET_OMAP_CLASS ((system_rev >> 24) & 0xff)
+#define GET_OMAP_CLASS (system_rev & 0xff)
 
 #define IS_OMAP_CLASS(class, id)                       \
 static inline int is_omap ##class (void)               \
@@ -320,39 +325,20 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define cpu_class_is_omap2()   (cpu_is_omap24xx() || cpu_is_omap34xx())
 
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-/*
- * Macros to detect silicon revision of OMAP2/3 processors.
- * is_sil_rev_greater_than:    true if passed cpu type & its rev is greater.
- * is_sil_rev_lesser_than:     true if passed cpu type & its rev is lesser.
- * is_sil_rev_equal_to:                true if passed cpu type & its rev is equal.
- * get_sil_rev:                        return the silicon rev value.
- */
-#define get_sil_omap_type(rev) ((rev & 0xffff0000) >> 16)
-#define get_sil_revision(rev)  ((rev & 0x0000f000) >> 12)
-
-#define is_sil_rev_greater_than(rev) \
-               ((get_sil_omap_type(system_rev) == get_sil_omap_type(rev)) && \
-               (get_sil_revision(system_rev) > get_sil_revision(rev)))
 
-#define is_sil_rev_less_than(rev) \
-               ((get_sil_omap_type(system_rev) == get_sil_omap_type(rev)) && \
-               (get_sil_revision(system_rev) < get_sil_revision(rev)))
+/* Various silicon revisions for omap2 */
+#define OMAP242X_CLASS         0x24200024
+#define OMAP2420_REV_ES1_0     0x24200024
+#define OMAP2420_REV_ES2_0     0x24201024
 
-#define is_sil_rev_equal_to(rev) \
-               ((get_sil_omap_type(system_rev) == get_sil_omap_type(rev)) && \
-               (get_sil_revision(system_rev) == get_sil_revision(rev)))
+#define OMAP243X_CLASS         0x24300024
+#define OMAP2430_REV_ES1_0     0x24300024
 
-#define get_sil_rev() \
-               get_sil_revision(system_rev)
-
-/* Various silicon macros defined here */
-#define OMAP2420_REV_ES1_0     0x24200000
-#define OMAP2420_REV_ES2_0     0x24201000
-#define OMAP2430_REV_ES1_0     0x24300000
-#define OMAP3430_REV_ES1_0     0x34300000
-#define OMAP3430_REV_ES2_0     0x34301000
-#define OMAP3430_REV_ES2_1     0x34302000
-#define OMAP3430_REV_ES2_2     0x34303000
+#define OMAP343X_CLASS         0x34300034
+#define OMAP3430_REV_ES1_0     0x34300034
+#define OMAP3430_REV_ES2_0     0x34301034
+#define OMAP3430_REV_ES2_1     0x34302034
+#define OMAP3430_REV_ES3_0     0x34303034
 
 /*
  * omap_chip bits
@@ -377,23 +363,16 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define CHIP_IS_OMAP24XX       (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
 
 int omap_chip_is(struct omap_chip_id oci);
-
+int omap_type(void);
 
 /*
  * Macro to detect device type i.e. EMU/HS/TST/GP/BAD
  */
-#define DEVICE_TYPE_TEST       0
-#define DEVICE_TYPE_EMU                1
-#define DEVICE_TYPE_SEC                2
-#define DEVICE_TYPE_GP         3
-#define DEVICE_TYPE_BAD                4
-
-#define get_device_type()      ((system_rev & 0x700) >> 8)
-#define is_device_type_test()  (get_device_type() == DEVICE_TYPE_TEST)
-#define is_device_type_emu()   (get_device_type() == DEVICE_TYPE_EMU)
-#define is_device_type_sec()   (get_device_type() == DEVICE_TYPE_SEC)
-#define is_device_type_gp()    (get_device_type() == DEVICE_TYPE_GP)
-#define is_device_type_bad()   (get_device_type() == DEVICE_TYPE_BAD)
+#define OMAP2_DEVICE_TYPE_TEST         0
+#define OMAP2_DEVICE_TYPE_EMU          1
+#define OMAP2_DEVICE_TYPE_SEC          2
+#define OMAP2_DEVICE_TYPE_GP           3
+#define OMAP2_DEVICE_TYPE_BAD          4
 
 void omap2_check_revision(void);
 
index 1b0039bdeb4ee28c0501e94d9c15afe9c060858e..1b11f5c6a2d9769d4acdc543a5fba4bd1a03636d 100644 (file)
 #ifdef CONFIG_OMAP_LL_DEBUG_UART3
                add     \rx, \rx, #0x00004000   @ UART 3
 #endif
+
+#elif  CONFIG_ARCH_OMAP3
+               moveq   \rx, #0x48000000        @ physical base address
+               movne   \rx, #0xd8000000        @ virtual base
+               orr     \rx, \rx, #0x0006a000
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
+               add     \rx, \rx, #0x00002000   @ UART 2
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART3
+               add     \rx, \rx, #0x00fb0000   @ UART 3
+               add     \rx, \rx, #0x00006000
+#endif
 #endif
                .endm
 
diff --git a/arch/arm/plat-omap/include/mach/dsp.h b/arch/arm/plat-omap/include/mach/dsp.h
new file mode 100644 (file)
index 0000000..ae71eb8
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __ARCH_OMAP_DSP_H
+#define __ARCH_OMAP_DSP_H
+
+/*
+ * for /dev/dspctl/ctl
+ */
+#define DSPCTL_IOCTL_RESET             1
+#define DSPCTL_IOCTL_RUN               2
+#define DSPCTL_IOCTL_SETRSTVECT                3
+#ifdef CONFIG_ARCH_OMAP1
+#define DSPCTL_IOCTL_CPU_IDLE          4
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_ON  5
+#define DSPCTL_IOCTL_MPUI_WORDSWAP_OFF 6
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_ON  7
+#define DSPCTL_IOCTL_MPUI_BYTESWAP_OFF 8
+#define DSPCTL_IOCTL_GBL_IDLE          9
+#endif /* CONFIG_ARCH_OMAP1 */
+#define DSPCTL_IOCTL_DSPCFG            10
+#define DSPCTL_IOCTL_DSPUNCFG          11
+#define DSPCTL_IOCTL_TASKCNT           12
+#define DSPCTL_IOCTL_POLL              13
+#define DSPCTL_IOCTL_REGMEMR           40
+#define DSPCTL_IOCTL_REGMEMW           41
+#define DSPCTL_IOCTL_REGIOR            42
+#define DSPCTL_IOCTL_REGIOW            43
+#define DSPCTL_IOCTL_GETVAR            44
+#define DSPCTL_IOCTL_SETVAR            45
+#define DSPCTL_IOCTL_RUNLEVEL          50
+#define DSPCTL_IOCTL_SUSPEND           51
+#define DSPCTL_IOCTL_RESUME            52
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+#define DSPCTL_IOCTL_FBEN              53
+#define DSPCTL_IOCTL_FBDIS             54
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+#define DSPCTL_IOCTL_MBSEND            99
+
+struct omap_dsp_mailbox_cmd {
+       __u16   cmd;
+       __u16   data;
+};
+
+struct omap_dsp_reginfo {
+       __u16   adr;
+       __u16   val;
+};
+
+struct omap_dsp_varinfo {
+       __u8    varid;
+       __u16   val[0];
+};
+
+/*
+ * for taskdev
+ * (ioctls below should be >= 0x10000)
+ */
+#define TASK_IOCTL_BFLSH       0x10000
+#define TASK_IOCTL_SETBSZ      0x10001
+#define TASK_IOCTL_LOCK                0x10002
+#define TASK_IOCTL_UNLOCK      0x10003
+#define TASK_IOCTL_GETNAME     0x10004
+
+/*
+ * for /dev/dspctl/mem
+ */
+#define MEM_IOCTL_EXMAP                1
+#define MEM_IOCTL_EXUNMAP      2
+#define MEM_IOCTL_EXMAP_FLUSH  3
+#define MEM_IOCTL_FBEXPORT     5
+#define MEM_IOCTL_MMUITACK     7
+#define MEM_IOCTL_MMUINIT      9
+#define MEM_IOCTL_KMEM_RESERVE 11
+#define MEM_IOCTL_KMEM_RELEASE 12
+
+struct omap_dsp_mapinfo {
+       __u32   dspadr;
+       __u32   size;
+};
+
+/*
+ * for /dev/dspctl/twch
+ */
+#define TWCH_IOCTL_MKDEV       1
+#define TWCH_IOCTL_RMDEV       2
+#define TWCH_IOCTL_TADD                11
+#define TWCH_IOCTL_TDEL                12
+#define TWCH_IOCTL_TKILL       13
+
+struct omap_dsp_taddinfo {
+       __u8    minor;
+       __u32   taskadr;
+};
+
+#define TADD_ABORTADR  0xffffffff
+
+#endif /* __ARCH_OMAP_DSP_H */
index da97736f3efae3105dffcbaae511ef618d725f62..0c7565eb6ce82be1a14493228fc48c34c92650a9 100644 (file)
@@ -5,25 +5,50 @@
  *
  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #ifndef ASM_ARCH_DSP_COMMON_H
 #define ASM_ARCH_DSP_COMMON_H
 
+#include <linux/clk.h>
+
+struct dsp_kfunc_device {
+       char            *name;
+       struct clk      *fck;
+       struct clk      *ick;;
+       spinlock_t       lock;
+       int              enabled;
+       int              type;
+#define DSP_KFUNC_DEV_TYPE_COMMON      1
+#define DSP_KFUNC_DEV_TYPE_AUDIO       2
+
+       struct list_head        entry;
+
+       int     (*probe)(struct dsp_kfunc_device *, int);
+       int     (*remove)(struct dsp_kfunc_device *, int);
+       int     (*enable)(struct dsp_kfunc_device *, int);
+       int     (*disable)(struct dsp_kfunc_device *, int);
+};
+
+extern int dsp_kfunc_device_register(struct dsp_kfunc_device *);
+
+struct dsp_platform_data {
+       struct list_head kdev_list;
+};
+
+struct omap_dsp {
+       struct mutex            lock;
+       int                     enabled;        /* stored peripheral status */
+       struct omap_mmu         *mmu;
+       struct omap_mbox        *mbox;
+       struct device           *dev;
+       struct list_head        *kdev_list;
+       int                     initialized;
+};
+
 #if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
 extern void omap_dsp_request_mpui(void);
 extern void omap_dsp_release_mpui(void);
index d4e9043bf2013c23b08f34c9eefcba9322059c45..a8fca9d9845b00102ba036958736452a78b89a54 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/entry-macro.S
+ * include/asm-arm/arch-omap/entry-macro.S
  *
  * Low-level IRQ helper macros for OMAP-based platforms
  *
 1510:
                .endm
 
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#endif
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 
+#if defined(CONFIG_ARCH_OMAP24XX)
 #include <mach/omap24xx.h>
+#endif
+#if defined(CONFIG_ARCH_OMAP34XX)
+#include <mach/omap34xx.h>
+#endif
+
+#define INTCPS_SIR_IRQ_OFFSET  0x0040          /* Active interrupt number */
 
                .macro  disable_fiq
                .endm
@@ -79,7 +87,7 @@
                ldr     \irqnr, [\base, #0xd8] /* IRQ pending reg 3 */
                cmp     \irqnr, #0x0
 2222:
-               ldrne   \irqnr, [\base, #IRQ_SIR_IRQ]
+               ldrne   \irqnr, [\base, #INTCPS_SIR_IRQ_OFFSET]
 
                .endm
 
index c92e4b42b2899cc0e6fdad376813815734cd5341..47543545a1cef8adae7959f08cec36834165259c 100644 (file)
@@ -34,9 +34,9 @@ extern void omap1510_fpga_init_irq(void);
  * ---------------------------------------------------------------------------
  */
 /* maps in the FPGA registers and the ETHR registers */
-#define H2P2_DBG_FPGA_BASE             0xE8000000      /* VA */
-#define H2P2_DBG_FPGA_SIZE             SZ_4K           /* SIZE */
-#define H2P2_DBG_FPGA_START            0x04000000      /* PA */
+#define H2P2_DBG_FPGA_BASE             ((void __iomem *)0xE8000000)    /* VA */
+#define H2P2_DBG_FPGA_SIZE             SZ_4K                           /* SIZE */
+#define H2P2_DBG_FPGA_START            0x04000000                      /* PA */
 
 #define H2P2_DBG_FPGA_ETHR_START       (H2P2_DBG_FPGA_START + 0x300)
 #define H2P2_DBG_FPGA_FPGA_REV         (H2P2_DBG_FPGA_BASE + 0x10)     /* FPGA Revision */
@@ -85,9 +85,9 @@ struct h2p2_dbg_fpga {
  *  OMAP-1510 FPGA
  * ---------------------------------------------------------------------------
  */
-#define OMAP1510_FPGA_BASE                     0xE8000000      /* Virtual */
-#define OMAP1510_FPGA_SIZE                     SZ_4K
-#define OMAP1510_FPGA_START                    0x08000000      /* Physical */
+#define OMAP1510_FPGA_BASE             ((void __iomem *)0xE8000000)    /* VA */
+#define OMAP1510_FPGA_SIZE             SZ_4K
+#define OMAP1510_FPGA_START            0x08000000                      /* PA */
 
 /* Revision */
 #define OMAP1510_FPGA_REV_LOW                  (OMAP1510_FPGA_BASE + 0x0)
index 10da0e07c0cf8998b926a3680b042936e77e5129..a143253969ceef529d5f5022459d43b0dc3e15a9 100644 (file)
@@ -48,7 +48,11 @@ struct omap_gpio_switch {
 };
 
 /* Call at init time only */
+#ifdef CONFIG_OMAP_GPIO_SWITCH
 extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
                                        int count);
+#else
+#define omap_register_gpio_switches(tbl, count)        do { } while (0)
+#endif
 
 #endif
index 94ce2780e8ee88090b23b62351498cdcb7c323c6..5f996f350c84e5df1ffc533b02038a57f2a0162b 100644 (file)
 #ifndef __ASM_ARCH_OMAP_GPIO_H
 #define __ASM_ARCH_OMAP_GPIO_H
 
+#include <linux/io.h>
 #include <mach/irqs.h>
-#include <asm/io.h>
 
-#define OMAP_MPUIO_BASE                        (void __iomem *)0xfffb5000
+#define OMAP_MPUIO_BASE                        0xfffb5000
 
 #ifdef CONFIG_ARCH_OMAP730
 #define OMAP_MPUIO_INPUT_LATCH         0x00
@@ -76,6 +76,8 @@ extern void omap_free_gpio(int gpio);
 extern void omap_set_gpio_direction(int gpio, int is_input);
 extern void omap_set_gpio_dataout(int gpio, int enable);
 extern int omap_get_gpio_datain(int gpio);
+extern void omap2_gpio_prepare_for_retention(void);
+extern void omap2_gpio_resume_after_retention(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
 
@@ -107,16 +109,24 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       if (gpio < (OMAP_MAX_GPIO_LINES + 16))
-               return OMAP_GPIO_IRQ(gpio);
-       return -EINVAL;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned irq)
 {
+       int tmp;
+
+       /* omap1 SOC mpuio */
        if (cpu_class_is_omap1() && (irq < (IH_MPUIO_BASE + 16)))
                return (irq - IH_MPUIO_BASE) + OMAP_MAX_GPIO_LINES;
-       return irq - IH_GPIO_BASE;
+
+       /* SOC gpio */
+       tmp = irq - IH_GPIO_BASE;
+       if (tmp < OMAP_MAX_GPIO_LINES)
+               return tmp;
+
+       /* we don't supply reverse mappings for non-SOC gpios */
+       return -EIO;
 }
 
 #endif
index 6a8e07ffc2d03431b5da8b43b6a67122a212c071..b0b2edf8c550615372c50f538da9aaf3c49a26a3 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef __OMAP2_GPMC_H
 #define __OMAP2_GPMC_H
 
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM            8
+
 #define GPMC_CS_CONFIG1                0x00
 #define GPMC_CS_CONFIG2                0x04
 #define GPMC_CS_CONFIG3                0x08
 #define GPMC_CS_NAND_ADDRESS   0x20
 #define GPMC_CS_NAND_DATA      0x24
 
+/*
+ * The following gpmc registers are being used by
+ * nand driver and hence is defined here.
+ * TBD: Move them to gpmc.c by providing appropriate
+ *  methods to read and write into these registers
+ */
+#define GPMC_IRQSTATUS         0x18
+#define GPMC_CONFIG            0x50
+#define GPMC_STATUS            0x54
+#define GPMC_CS0_BASE           0x60
+#define GPMC_CS_SIZE            0x30
+
+
 #define GPMC_CONFIG1_WRAPBURST_SUPP     (1 << 31)
 #define GPMC_CONFIG1_READMULTIPLE_SUPP  (1 << 30)
 #define GPMC_CONFIG1_READTYPE_ASYNC     (0 << 29)
@@ -78,9 +94,14 @@ struct gpmc_timings {
        u16 access;             /* Start-cycle to first data valid delay */
        u16 rd_cycle;           /* Total read cycle time */
        u16 wr_cycle;           /* Total write cycle time */
+
+       /* The following are only on OMAP3430 */
+       u16 wr_access;          /* WRACCESSTIME */
+       u16 wr_data_mux_bus;    /* WRDATAONADMUXBUS */
 };
 
 extern unsigned int gpmc_ns_to_ticks(unsigned int time_ns);
+extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
 extern unsigned int gpmc_round_ns_to_ticks(unsigned int time_ns);
 extern unsigned long gpmc_get_fclk_period(void);
 
@@ -92,5 +113,6 @@ 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);
+extern void __init gpmc_init(void);
 
 #endif
index 07f5d7f21528874c11091d7ec982c87465a051d6..3486524071b809c0cb41935c9fc0c82aded47622 100644 (file)
@@ -89,7 +89,7 @@
 #define DPLL_CTL               (0xfffecf00)
 
 /* DSP clock control. Must use __raw_readw() and __raw_writew() with these */
-#define DSP_CONFIG_REG_BASE     (0xe1008000)
+#define DSP_CONFIG_REG_BASE     IOMEM(0xe1008000)
 #define DSP_CKCTL              (DSP_CONFIG_REG_BASE + 0x0)
 #define DSP_IDLECT1            (DSP_CONFIG_REG_BASE + 0x4)
 #define DSP_IDLECT2            (DSP_CONFIG_REG_BASE + 0x8)
 
 #include "omap730.h"
 #include "omap1510.h"
-#include "omap24xx.h"
 #include "omap16xx.h"
+#include "omap24xx.h"
 #include "omap34xx.h"
 
 #ifndef __ASSEMBLER__
 #include "board-h4.h"
 #endif
 
+#if defined(CONFIG_MACH_NOKIA_N800) || defined(CONFIG_MACH_NOKIA770)
+#include "board-nokia.h"
+#endif
+
 #ifdef CONFIG_MACH_OMAP_2430SDP
 #include "board-2430sdp.h"
 #endif
 
+#ifdef CONFIG_MACH_OMAP2EVM
+#include "board-omap2evm.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_3430SDP
+#include "board-3430sdp.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP3EVM
+#include "board-omap3evm.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP3_BEAGLE
+#include "board-omap3beagle.h"
+#endif
+
+#ifdef CONFIG_MACH_OMAP_LDP
+#include "board-ldp.h"
+#endif
+
 #ifdef CONFIG_MACH_OMAP_APOLLON
 #include "board-apollon.h"
 #endif
diff --git a/arch/arm/plat-omap/include/mach/hsmmc.h b/arch/arm/plat-omap/include/mach/hsmmc.h
new file mode 100644 (file)
index 0000000..587e8ab
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * include/asm-arm/arch-omap/hsmmc.h
+ *
+ * Hardware definitions for SD/MMC Controller on OMAP243x and OMAP34xx
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_HSMMC_H
+#define __ASM_ARCH_OMAP_HSMMC_H
+
+extern void hsmmc_init(void);
+
+#endif /* __ASM_ARCH_OMAP_HSMMC_H */
+
index 2a30b7d88cdeae71cff778ae13c90bbb65d950f7..ea552674370600996cd501a48951134e2b1a9539 100644 (file)
 
 #if defined(CONFIG_ARCH_OMAP1)
 
-#define IO_PHYS                0xFFFB0000
-#define IO_OFFSET      0x01000000      /* Virtual IO = 0xfefb0000 */
-#define IO_SIZE                0x40000
-#define IO_VIRT                (IO_PHYS - IO_OFFSET)
-#define IO_ADDRESS(pa) ((pa) - IO_OFFSET)
-#define OMAP1_IO_ADDRESS(pa)   ((pa) - IO_OFFSET)
-#define io_p2v(pa)     ((pa) - IO_OFFSET)
-#define io_v2p(va)     ((va) + IO_OFFSET)
+#define IO_PHYS                        0xFFFB0000
+#define IO_OFFSET              0x01000000      /* Virtual IO = 0xfefb0000 */
+#define IO_SIZE                        0x40000
+#define IO_VIRT                        (IO_PHYS - IO_OFFSET)
+#define __IO_ADDRESS(pa)       ((pa) - IO_OFFSET)
+#define __OMAP1_IO_ADDRESS(pa) ((pa) - IO_OFFSET)
+#define io_v2p(va)             ((va) + IO_OFFSET)
 
 #elif defined(CONFIG_ARCH_OMAP2)
 
@@ -74,7 +73,6 @@
 #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_SMS_VIRT      0xFC000000
 #define OMAP243X_SMS_SIZE      SZ_1M
 
-#endif
-
-#define IO_OFFSET      0x90000000
-#define IO_ADDRESS(pa) ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
-#define OMAP2_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 */
+#define IO_OFFSET              0x90000000
+#define __IO_ADDRESS(pa)       ((pa) + IO_OFFSET)      /* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(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      OMAP2420_DSP_MEM_BASE   /* 0x58000000 */
 
 
 #define IO_OFFSET              0x90000000
-#define IO_ADDRESS(pa)         ((pa) + IO_OFFSET)/* Works for L3 and L4 */
-#define OMAP2_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_ADDRESS(pa)       ((pa) + IO_OFFSET)/* Works for L3 and L4 */
+#define __OMAP2_IO_ADDRESS(pa) ((pa) + IO_OFFSET)/* Works for L3 and L4 */
 #define io_v2p(va)             ((va) - IO_OFFSET)/* Works for L3 and L4 */
 
 /* DSP */
 
 #endif
 
-#ifndef __ASSEMBLER__
+#define IO_ADDRESS(pa)         IOMEM(__IO_ADDRESS(pa))
+#define OMAP1_IO_ADDRESS(pa)   IOMEM(__OMAP1_IO_ADDRESS(pa))
+#define OMAP2_IO_ADDRESS(pa)   IOMEM(__OMAP2_IO_ADDRESS(pa))
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x)               x
+#else
+#define IOMEM(x)               ((void __force __iomem *)(x))
 
 /*
  * Functions to access the OMAP IO region
  *      - DO NOT use hardcoded virtual addresses to allow changing the
  *        IO address space again if needed
  */
-#define omap_readb(a)          (*(volatile unsigned char  *)IO_ADDRESS(a))
-#define omap_readw(a)          (*(volatile unsigned short *)IO_ADDRESS(a))
-#define omap_readl(a)          (*(volatile unsigned int   *)IO_ADDRESS(a))
+#define omap_readb(a)          __raw_readb(IO_ADDRESS(a))
+#define omap_readw(a)          __raw_readw(IO_ADDRESS(a))
+#define omap_readl(a)          __raw_readl(IO_ADDRESS(a))
 
-#define omap_writeb(v,a)       (*(volatile unsigned char  *)IO_ADDRESS(a) = (v))
-#define omap_writew(v,a)       (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
-#define omap_writel(v,a)       (*(volatile unsigned int   *)IO_ADDRESS(a) = (v))
+#define omap_writeb(v,a)       __raw_writeb(v, IO_ADDRESS(a))
+#define omap_writew(v,a)       __raw_writew(v, IO_ADDRESS(a))
+#define omap_writel(v,a)       __raw_writel(v, IO_ADDRESS(a))
+
+struct omap_sdrc_params;
 
 extern void omap1_map_common_io(void);
 extern void omap1_init_common_hw(void);
 
 extern void omap2_map_common_io(void);
-extern void omap2_init_common_hw(void);
+extern void omap2_init_common_hw(struct omap_sdrc_params *sp);
+
+#define __arch_ioremap(p,s,t)  omap_ioremap(p,s,t)
+#define __arch_iounmap(v)      omap_iounmap(v)
+
+void __iomem *omap_ioremap(unsigned long phys, size_t size, unsigned int type);
+void omap_iounmap(volatile void __iomem *addr);
 
 #endif
 
index 17248bbf3f27e5bbfe3dfc0d54bf260183f80bfa..8a4473e94f1cce5d2aec5d36d474bb457a657cc4 100644 (file)
 #define INT_UART2              (15 + IH2_BASE)
 #define INT_BT_MCSI1TX         (16 + IH2_BASE)
 #define INT_BT_MCSI1RX         (17 + IH2_BASE)
+#define INT_SOSSI_MATCH                (19 + IH2_BASE)
 #define INT_USB_W2FC           (20 + IH2_BASE)
 #define INT_1WIRE              (21 + IH2_BASE)
 #define INT_OS_TIMER           (22 + IH2_BASE)
 #define INT_1610_DMA_CH14      (61 + IH2_BASE)
 #define INT_1610_DMA_CH15      (62 + IH2_BASE)
 #define INT_1610_NAND          (63 + IH2_BASE)
+#define INT_1610_SHA1MD5       (91 + IH2_BASE)
 
 /*
  * OMAP-730 specific IRQ numbers for interrupt handler 2
 #define INT_24XX_GPTIMER10     46
 #define INT_24XX_GPTIMER11     47
 #define INT_24XX_GPTIMER12     48
+#define INT_24XX_SHA1MD5       51
+#define INT_24XX_MCBSP4_IRQ_TX 54
+#define INT_24XX_MCBSP4_IRQ_RX 55
 #define INT_24XX_I2C1_IRQ      56
 #define INT_24XX_I2C2_IRQ      57
+#define INT_24XX_HDQ_IRQ       58
 #define INT_24XX_MCBSP1_IRQ_TX 59
 #define INT_24XX_MCBSP1_IRQ_RX 60
 #define INT_24XX_MCBSP2_IRQ_TX 62
 #define INT_24XX_MCBSP2_IRQ_RX 63
+#define INT_24XX_SPI1_IRQ      65
+#define INT_24XX_SPI2_IRQ      66
 #define INT_24XX_UART1_IRQ     72
 #define INT_24XX_UART2_IRQ     73
 #define INT_24XX_UART3_IRQ     74
 #define INT_24XX_USB_IRQ_HGEN  78
 #define INT_24XX_USB_IRQ_HSOF  79
 #define INT_24XX_USB_IRQ_OTG   80
+#define INT_24XX_MCBSP5_IRQ_TX 81
+#define INT_24XX_MCBSP5_IRQ_RX 82
 #define INT_24XX_MMC_IRQ       83
+#define INT_24XX_MMC2_IRQ      86
+#define INT_24XX_MCBSP3_IRQ_TX 89
+#define INT_24XX_MCBSP3_IRQ_RX 90
+#define INT_24XX_SPI3_IRQ      91
+
+#define INT_243X_MCBSP2_IRQ    16
+#define INT_243X_MCBSP3_IRQ    17
+#define INT_243X_MCBSP4_IRQ    18
+#define INT_243X_MCBSP5_IRQ    19
+#define INT_243X_MCBSP1_IRQ    64
+#define INT_243X_HS_USB_MC     92
+#define INT_243X_HS_USB_DMA    93
+#define INT_243X_CARKIT_IRQ    94
+
+#define INT_34XX_ST_MCBSP2_IRQ 4
+#define INT_34XX_ST_MCBSP3_IRQ 5
+#define INT_34XX_SSM_ABORT_IRQ 6
+#define INT_34XX_SYS_NIRQ      7
+#define INT_34XX_D2D_FW_IRQ    8
+#define INT_34XX_PRCM_MPU_IRQ  11
+#define INT_34XX_MCBSP1_IRQ    16
+#define INT_34XX_MCBSP2_IRQ    17
+#define INT_34XX_MCBSP3_IRQ    22
+#define INT_34XX_MCBSP4_IRQ    23
+#define INT_34XX_CAM_IRQ       24
+#define INT_34XX_MCBSP5_IRQ    27
+#define INT_34XX_GPIO_BANK1    29
+#define INT_34XX_GPIO_BANK2    30
+#define INT_34XX_GPIO_BANK3    31
+#define INT_34XX_GPIO_BANK4    32
+#define INT_34XX_GPIO_BANK5    33
+#define INT_34XX_GPIO_BANK6    34
+#define INT_34XX_USIM_IRQ      35
+#define INT_34XX_WDT3_IRQ      36
+#define INT_34XX_SPI4_IRQ      48
+#define INT_34XX_SHA1MD52_IRQ  49
+#define INT_34XX_FPKA_READY_IRQ        50
+#define INT_34XX_SHA1MD51_IRQ  51
+#define INT_34XX_RNG_IRQ       52
+#define INT_34XX_I2C3_IRQ      61
+#define INT_34XX_FPKA_ERROR_IRQ        64
+#define INT_34XX_PBIAS_IRQ     75
+#define INT_34XX_OHCI_IRQ      76
+#define INT_34XX_EHCI_IRQ      77
+#define INT_34XX_TLL_IRQ       78
+#define INT_34XX_PARTHASH_IRQ  79
+#define INT_34XX_MMC3_IRQ      94
+#define INT_34XX_GPT12_IRQ     95
 
 /* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
  * 16 MPUIO lines */
 
 /* External TWL4030 gpio interrupts are optional */
 #define TWL4030_GPIO_IRQ_BASE  TWL4030_PWR_IRQ_END
-#ifdef CONFIG_TWL4030_GPIO
+#ifdef CONFIG_GPIO_TWL4030
 #define TWL4030_GPIO_NR_IRQS   18
 #else
 #define        TWL4030_GPIO_NR_IRQS    0
 
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
+extern int omap_irq_pending(void);
 #endif
 
 #include <mach/hardware.h>
index 232923aaf61d34ed0f66daf5af54d1fad7c73a13..ba1c95c7c8cbea22d1b7d7308312fc6f3d2ea7f5 100644 (file)
@@ -14,6 +14,7 @@ struct omap_kp_platform_data {
        int rows;
        int cols;
        int *keymap;
+       int irq;
        unsigned int keymapsize;
        unsigned int rep:1;
        unsigned long delay;
index 7cbed9332e169f36854349048051cf02b979144e..9d3994b7ff62ed31d4bd7d14d2cdee7c288c329e 100644 (file)
@@ -61,6 +61,8 @@ struct omap_mbox {
        void                    (*err_notify)(void);
 };
 
+extern struct omap_mbox mbox_dsp_info;
+
 int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg, void *);
 void omap_mbox_init_seq(struct omap_mbox *);
 
index 8fdb95e26fcd86775fe4fd494139e381b17f76e5..6a0d1a0a24a7d86f2f767130de8ed9ea95073e3c 100644 (file)
 
 #define OMAP24XX_MCBSP1_BASE   0x48074000
 #define OMAP24XX_MCBSP2_BASE   0x48076000
+#define OMAP2430_MCBSP3_BASE   0x4808c000
+#define OMAP2430_MCBSP4_BASE   0x4808e000
+#define OMAP2430_MCBSP5_BASE   0x48096000
 
 #define OMAP34XX_MCBSP1_BASE   0x48074000
 #define OMAP34XX_MCBSP2_BASE   0x49022000
+#define OMAP34XX_MCBSP3_BASE   0x49024000
+#define OMAP34XX_MCBSP4_BASE   0x49026000
+#define OMAP34XX_MCBSP5_BASE   0x48096000
 
 #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP730)
 
@@ -81,9 +87,6 @@
 #define OMAP_MCBSP_REG_XCERG   0x3A
 #define OMAP_MCBSP_REG_XCERH   0x3C
 
-#define OMAP_MAX_MCBSP_COUNT   3
-#define MAX_MCBSP_CLOCKS       3
-
 #define AUDIO_MCBSP_DATAWRITE  (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1)
 #define AUDIO_MCBSP_DATAREAD   (OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1)
 
 #define AUDIO_DMA_TX           OMAP_DMA_MCBSP1_TX
 #define AUDIO_DMA_RX           OMAP_DMA_MCBSP1_RX
 
-#elif defined(CONFIG_ARCH_OMAP24XX)
+#elif defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 
 #define OMAP_MCBSP_REG_DRR2    0x00
 #define OMAP_MCBSP_REG_DRR1    0x04
 #define OMAP_MCBSP_REG_DXR2    0x08
 #define OMAP_MCBSP_REG_DXR1    0x0C
+#define OMAP_MCBSP_REG_DRR     0x00
+#define OMAP_MCBSP_REG_DXR     0x08
 #define OMAP_MCBSP_REG_SPCR2   0x10
 #define OMAP_MCBSP_REG_SPCR1   0x14
 #define OMAP_MCBSP_REG_RCR2    0x18
 #define OMAP_MCBSP_REG_RCERH   0x70
 #define OMAP_MCBSP_REG_XCERG   0x74
 #define OMAP_MCBSP_REG_XCERH   0x78
-
-#define OMAP_MAX_MCBSP_COUNT   2
-#define MAX_MCBSP_CLOCKS       2
+#define OMAP_MCBSP_REG_SYSCON  0x8C
+#define OMAP_MCBSP_REG_XCCR    0xAC
+#define OMAP_MCBSP_REG_RCCR    0xB0
 
 #define AUDIO_MCBSP_DATAWRITE  (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1)
 #define AUDIO_MCBSP_DATAREAD   (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
 
 #endif
 
-#define OMAP_MCBSP_READ(base, reg)             __raw_readw((base) + OMAP_MCBSP_REG_##reg)
-#define OMAP_MCBSP_WRITE(base, reg, val)       __raw_writew((val), (base) + OMAP_MCBSP_REG_##reg)
-
-
 /************************** McBSP SPCR1 bit definitions ***********************/
 #define RRST                   0x0001
 #define RRDY                   0x0002
 #define DXENA                  0x0080
 #define CLKSTP(value)          ((value)<<11)   /* bits 11:12 */
 #define RJUST(value)           ((value)<<13)   /* bits 13:14 */
+#define ALB                    0x8000
 #define DLB                    0x8000
 
 /************************** McBSP SPCR2 bit definitions ***********************/
 #define XPABLK(value)          ((value)<<5)    /* Bits 5:6 */
 #define XPBBLK(value)          ((value)<<7)    /* Bits 7:8 */
 
+/*********************** McBSP XCCR bit definitions *************************/
+#define DILB                   0x0020
+#define XDMAEN                 0x0008
+#define XDISABLE               0x0001
+
+/********************** McBSP RCCR bit definitions *************************/
+#define RDMAEN                 0x0008
+#define RDISABLE               0x0001
+
+/********************** McBSP SYSCONFIG bit definitions ********************/
+#define SOFTRST                        0x0002
 
 /* we don't do multichannel for now */
 struct omap_mcbsp_reg_cfg {
@@ -260,6 +273,8 @@ typedef enum {
        OMAP_MCBSP1 = 0,
        OMAP_MCBSP2,
        OMAP_MCBSP3,
+       OMAP_MCBSP4,
+       OMAP_MCBSP5
 } omap_mcbsp_id;
 
 typedef int __bitwise omap_mcbsp_io_type_t;
@@ -311,12 +326,10 @@ struct omap_mcbsp_spi_cfg {
 struct omap_mcbsp_ops {
        void (*request)(unsigned int);
        void (*free)(unsigned int);
-       int (*check)(unsigned int);
 };
 
 struct omap_mcbsp_platform_data {
        unsigned long phys_base;
-       u32 virt_base;
        u8 dma_rx_sync, dma_tx_sync;
        u16 rx_irq, tx_irq;
        struct omap_mcbsp_ops *ops;
@@ -326,7 +339,7 @@ struct omap_mcbsp_platform_data {
 struct omap_mcbsp {
        struct device *dev;
        unsigned long phys_base;
-       u32 io_base;
+       void __iomem *io_base;
        u8 id;
        u8 free;
        omap_mcbsp_word_length rx_word_length;
@@ -354,6 +367,8 @@ struct omap_mcbsp {
        struct omap_mcbsp_platform_data *pdata;
        struct clk *clk;
 };
+extern struct omap_mcbsp **mcbsp_ptr;
+extern int omap_mcbsp_count;
 
 int omap_mcbsp_init(void);
 void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config,
@@ -378,5 +393,6 @@ void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg *
 /* Polled read/write functions */
 int omap_mcbsp_pollread(unsigned int id, u16 * buf);
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
+int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
 
 #endif
index a325caf80d04b9a18928a7b6478a64ab4f5338e3..2d80fa2639e1a703c6969dd63ffbb091ec3af3c3 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2000 RidgeRun, Inc.
  * Author: Greg Lonnon <glonnon@ridgerun.com>
  *
- * This file was derived from arch/arm/mach-intergrator/include/mach/memory.h
+ * This file was derived from linux/include/asm-arm/arch-intergrator/memory.h
  * Copyright (C) 1999 ARM Limited
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -38,7 +38,7 @@
  */
 #if defined(CONFIG_ARCH_OMAP1)
 #define PHYS_OFFSET            UL(0x10000000)
-#elif defined(CONFIG_ARCH_OMAP2)
+#elif defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 #define PHYS_OFFSET            UL(0x80000000)
 #endif
 
index fc15d13058fc74e5116490b4e704be355dd7b576..2f20789bd256a2c78b31d6baa220036fe5858155 100644 (file)
 
 #include <mach/board.h>
 
+#define OMAP15XX_NR_MMC                1
+#define OMAP16XX_NR_MMC                2
+#define OMAP1_MMC_SIZE         0x080
+#define OMAP1_MMC1_BASE                0xfffb7800
+#define OMAP1_MMC2_BASE                0xfffb7c00      /* omap16xx only */
+
+#define OMAP24XX_NR_MMC                2
+#define OMAP34XX_NR_MMC                3
+#define OMAP2420_MMC_SIZE      OMAP1_MMC_SIZE
+#define HSMMC_SIZE             0x200
+#define OMAP2_MMC1_BASE                0x4809c000
+#define OMAP2_MMC2_BASE                0x480b4000
+#define OMAP3_MMC3_BASE                0x480ad000
+
 #define OMAP_MMC_MAX_SLOTS     2
 
 struct omap_mmc_platform_data {
-       struct omap_mmc_conf    conf;
 
-       /* number of slots on board */
+       /* number of slots per controller */
        unsigned nr_slots:2;
 
        /* set if your board has components or wiring that limits the
@@ -41,7 +54,27 @@ struct omap_mmc_platform_data {
        int (*suspend)(struct device *dev, int slot);
        int (*resume)(struct device *dev, int slot);
 
+       u64 dma_mask;
+
        struct omap_mmc_slot_data {
+
+               /*
+                * nomux means "standard" muxing is wrong on this board, and
+                * that board-specific code handled it before common init logic.
+                */
+               unsigned nomux:1;
+
+               /* switch pin can be for card detect (default) or card cover */
+               unsigned cover:1;
+
+               /* 4 wire signaling is optional, and is only used for SD/SDIO */
+               unsigned wire4:1;
+
+               /* use the internal clock */
+               unsigned internal_clock:1;
+               s16 power_pin;
+               s16 switch_pin;
+
                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);
@@ -49,8 +82,8 @@ struct omap_mmc_platform_data {
                /* return MMC cover switch state, can be NULL if not supported.
                 *
                 * possible return values:
-                *   0 - open
-                *   1 - closed
+                *   0 - closed
+                *   1 - open
                 */
                int (* get_cover_state)(struct device *dev, int slot);
 
@@ -66,9 +99,35 @@ struct omap_mmc_platform_data {
        } 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_cover_event(struct device *dev, int slot, int is_closed);
 
+#if    defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
+       defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                               int nr_controllers);
+void omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                               int nr_controllers);
+int omap_mmc_add(int id, unsigned long base, unsigned long size,
+                       unsigned int irq, struct omap_mmc_platform_data *data);
+#else
+static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                               int nr_controllers)
+{
+}
+static inline void omap2_init_mmc(struct omap_mmc_platform_data **mmc_data,
+                               int nr_controllers)
+{
+}
+static inline int omap_mmc_add(int id, unsigned long base, unsigned long size,
+               unsigned int irq, struct omap_mmc_platform_data *data)
+{
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+void __init hsmmc_init(void);
+#endif
+
 #endif
diff --git a/arch/arm/plat-omap/include/mach/mmu.h b/arch/arm/plat-omap/include/mach/mmu.h
new file mode 100644 (file)
index 0000000..d970b71
--- /dev/null
@@ -0,0 +1,211 @@
+#ifndef __ARCH_OMAP_MMU_H
+#define __ARCH_OMAP_MMU_H
+
+#include <linux/device.h>
+#include <linux/workqueue.h>
+
+enum exmap_type {
+       EXMAP_TYPE_MEM,
+       EXMAP_TYPE_FB
+};
+
+enum omap_mmu_type {
+       OMAP_MMU_DSP,
+       OMAP_MMU_IVA1,
+       OMAP_MMU_CAMERA,
+};
+
+struct exmap_tbl {
+       unsigned int valid:1;
+       unsigned int prsvd:1;
+       int usecount;           /* reference count by mmap */
+       enum exmap_type type;
+       void *buf;              /* virtual address of the buffer,
+                                * i.e. 0xc0000000 - */
+       void *vadr;             /* DSP shadow space,
+                                * i.e. 0xe0000000 - 0xe0ffffff */
+       unsigned int order;
+       struct {
+               int prev;
+               int next;
+       } link;                 /* grouping */
+};
+
+struct cam_ram_regset {
+       union {
+               struct {
+                       u16 cam_l;
+                       u16 cam_h;
+               };
+
+               u32 cam;
+       };
+
+       union {
+               struct {
+                       u16 ram_l;
+                       u16 ram_h;
+               };
+
+               u32 ram;
+       };
+};
+
+struct omap_mmu_tlb_lock {
+       int base;
+       int victim;
+};
+
+struct omap_mmu;
+struct omap_mmu_tlb_entry;
+
+#ifdef CONFIG_ARCH_OMAP1
+extern struct omap_mmu_ops omap1_mmu_ops;
+extern void omap_mmu_itack(struct omap_mmu *mmu);
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct omap_mmu_ops omap2_mmu_ops;
+static inline void omap_mmu_itack(struct omap_mmu *mmu)
+{
+}
+#endif
+
+struct omap_mmu_ops {
+       int (*startup)(struct omap_mmu *mmu);
+       void (*shutdown)(struct omap_mmu *mmu);
+
+       /* TLB operations */
+       void (*read_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+       void (*load_tlb)(struct omap_mmu *, struct cam_ram_regset *);
+       ssize_t (*show)(struct omap_mmu *, char *, struct omap_mmu_tlb_lock *);
+
+       /* CAM / RAM operations */
+       struct cam_ram_regset *(*cam_ram_alloc)(struct omap_mmu *,
+                                               struct omap_mmu_tlb_entry *);
+       int (*cam_ram_valid)(struct cam_ram_regset *);
+       unsigned long (*cam_va)(struct cam_ram_regset *);
+
+       /* Memory operations */
+       int (*mem_enable)(struct omap_mmu *, void *);
+       int (*mem_disable)(struct omap_mmu *, void *);
+
+       void (*interrupt)(struct omap_mmu *);
+
+       /* PTE attribute operations */
+       pgprot_t (*pte_get_attr)(struct omap_mmu_tlb_entry *);
+};
+
+struct omap_mmu {
+       const char *name;
+       unsigned long base;
+       struct clk *clk;
+
+       unsigned long membase, memsize;
+       struct clk *memclk;
+
+       enum omap_mmu_type type;
+
+       struct device *dev;
+
+       struct rw_semaphore exmap_sem;
+       struct exmap_tbl *exmap_tbl;
+
+       unsigned int nr_tlb_entries;
+       unsigned int nr_exmap_preserved;
+
+       struct mm_struct *twl_mm;
+
+       /* Size of virtual address space, in bits */
+       unsigned int addrspace;
+
+       /* Interrupt */
+       unsigned int irq;
+       unsigned long fault_address;
+       struct work_struct irq_work;
+
+       struct omap_mmu_ops *ops;
+};
+
+#define omap_mmu_internal_memory(mmu, addr)                                    \
+       (likely(mmu->membase) && (((unsigned long)(addr) >= mmu->membase) &&    \
+                ((unsigned long)(addr) < mmu->membase + mmu->memsize)))
+
+#define INIT_EXMAP_TBL_ENTRY(ent, b, v, typ, od)       \
+do {                                           \
+       (ent)->buf              = (b);          \
+       (ent)->vadr             = (v);          \
+       (ent)->valid            = 1;            \
+       (ent)->prsvd            = 0;            \
+       (ent)->usecount         = 0;            \
+       (ent)->type             = (typ);        \
+       (ent)->order            = (od);         \
+       (ent)->link.next        = -1;           \
+       (ent)->link.prev        = -1;           \
+} while (0)
+
+#define INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(ent, b, v)  \
+do {                                                   \
+       (ent)->buf              = (b);                  \
+       (ent)->vadr             = (v);                  \
+       (ent)->valid            = 1;                    \
+       (ent)->prsvd            = 1;                    \
+       (ent)->usecount         = 0;                    \
+       (ent)->type             = EXMAP_TYPE_MEM;       \
+       (ent)->order            = 0;                    \
+       (ent)->link.next        = -1;                   \
+       (ent)->link.prev        = -1;                   \
+} while (0)
+
+#define omap_mmu_to_virt(mmu, db)      ((void *)((mmu)->membase + (db)))
+#define virt_to_omap_mmu(mmu, va) \
+       (((unsigned long)(va) - (mmu)->membase))
+
+/* arch/arm/plat-omap/mmu.c */
+int omap_mmu_register(struct omap_mmu *mmu);
+void omap_mmu_unregister(struct omap_mmu *mmu);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset);
+void omap_mmu_disable(struct omap_mmu *mmu);
+
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr);
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr);
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+                      struct cam_ram_regset *cr);
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *, struct omap_mmu_tlb_entry *);
+int omap_mmu_clear_tlb_entry(struct omap_mmu *, unsigned long vadr);
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry);
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr);
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size);
+void omap_mmu_kmem_release(void);
+
+unsigned long omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr,
+                                   size_t *len);
+
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long dspadr,
+                  unsigned long padr, unsigned long size,
+                  enum exmap_type type);
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long dspadr);
+void omap_mmu_exmap_flush(struct omap_mmu *mmu);
+void omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len);
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len);
+
+int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt,
+                    unsigned long phys, unsigned long size);
+void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt,
+                       unsigned long size);
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+                                   unsigned long dspadr, int index);
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long dspadr);
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len);
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu, struct bin_attribute *,
+                           char *buf, loff_t offset, size_t count);
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu, struct bin_attribute *,
+                           char *buf, loff_t offset, size_t count);
+
+#endif /* __ARCH_OMAP_MMU_H */
index 614b2c1327c747b77b5c693979babc566bd66d02..360840b03ff6937e56d7d5af7cacd079c41b9d78 100644 (file)
        .pu_pd_val      = pull_mode,                            \
 },
 
-
-#define PULL_DISABLED  0
-#define PULL_ENABLED   1
-
-#define PULL_DOWN      0
-#define PULL_UP                1
+/* 24xx/34xx mux bit defines */
+#define OMAP2_PULL_ENA         (1 << 3)
+#define OMAP2_PULL_UP          (1 << 4)
+#define OMAP2_ALTELECTRICALSEL (1 << 5)
+
+/* 34xx specific mux bit defines */
+#define OMAP3_INPUT_EN         (1 << 8)
+#define OMAP3_OFF_EN           (1 << 9)
+#define OMAP3_OFFOUT_EN                (1 << 10)
+#define OMAP3_OFFOUT_VAL       (1 << 11)
+#define OMAP3_OFF_PULL_EN      (1 << 12)
+#define OMAP3_OFF_PULL_UP      (1 << 13)
+#define OMAP3_WAKEUP_EN                (1 << 14)
+
+/* 34xx mux mode options for each pin. See TRM for options */
+#define        OMAP34XX_MUX_MODE0      0
+#define        OMAP34XX_MUX_MODE1      1
+#define        OMAP34XX_MUX_MODE2      2
+#define        OMAP34XX_MUX_MODE3      3
+#define        OMAP34XX_MUX_MODE4      4
+#define        OMAP34XX_MUX_MODE5      5
+#define        OMAP34XX_MUX_MODE6      6
+#define        OMAP34XX_MUX_MODE7      7
+
+/* 34xx active pin states */
+#define OMAP34XX_PIN_OUTPUT            0
+#define OMAP34XX_PIN_INPUT             OMAP3_INPUT_EN
+#define OMAP34XX_PIN_INPUT_PULLUP      (OMAP2_PULL_ENA | OMAP3_INPUT_EN \
+                                               | OMAP2_PULL_UP)
+#define OMAP34XX_PIN_INPUT_PULLDOWN    (OMAP2_PULL_ENA | OMAP3_INPUT_EN)
+
+/* 34xx off mode states */
+#define OMAP34XX_PIN_OFF_NONE           0
+#define OMAP34XX_PIN_OFF_OUTPUT_HIGH   (OMAP3_OFF_EN | OMAP3_OFFOUT_EN \
+                                               | OMAP3_OFFOUT_VAL)
+#define OMAP34XX_PIN_OFF_OUTPUT_LOW    (OMAP3_OFF_EN | OMAP3_OFFOUT_EN)
+#define OMAP34XX_PIN_OFF_INPUT_PULLUP  (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN \
+                                               | OMAP3_OFF_PULL_UP)
+#define OMAP34XX_PIN_OFF_INPUT_PULLDOWN        (OMAP3_OFF_EN | OMAP3_OFF_PULL_EN)
+#define OMAP34XX_PIN_OFF_WAKEUPENABLE  OMAP3_WAKEUP_EN
+
+#define MUX_CFG_34XX(desc, reg_offset, mux_value) {            \
+       .name           = desc,                                 \
+       .debug          = 0,                                    \
+       .mux_reg        = reg_offset,                           \
+       .mux_val        = mux_value                             \
+},
 
 struct pin_config {
-       char *name;
-       unsigned char busy;
-       unsigned char debug;
+       char                    *name;
+       const unsigned int      mux_reg;
+       unsigned char           debug;
 
-       const char *mux_reg_name;
-       const unsigned int mux_reg;
+#if    defined(CONFIG_ARCH_OMAP34XX)
+       u16                     mux_val; /* Wake-up, off mode, pull, mux mode */
+#endif
+
+#if    defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP24XX)
        const unsigned char mask_offset;
        const unsigned char mask;
 
@@ -150,6 +194,12 @@ struct pin_config {
        const char *pu_pd_name;
        const unsigned int pu_pd_reg;
        const unsigned char pu_pd_val;
+#endif
+
+#if    defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
+       const char *mux_reg_name;
+#endif
+
 };
 
 enum omap730_index {
@@ -593,6 +643,122 @@ enum omap24xx_index {
 
 };
 
+enum omap34xx_index {
+       /* 34xx I2C */
+       K21_34XX_I2C1_SCL,
+       J21_34XX_I2C1_SDA,
+       AF15_34XX_I2C2_SCL,
+       AE15_34XX_I2C2_SDA,
+       AF14_34XX_I2C3_SCL,
+       AG14_34XX_I2C3_SDA,
+       AD26_34XX_I2C4_SCL,
+       AE26_34XX_I2C4_SDA,
+
+       /* PHY - HSUSB: 12-pin ULPI PHY: Port 1*/
+       Y8_3430_USB1HS_PHY_CLK,
+       Y9_3430_USB1HS_PHY_STP,
+       AA14_3430_USB1HS_PHY_DIR,
+       AA11_3430_USB1HS_PHY_NXT,
+       W13_3430_USB1HS_PHY_DATA0,
+       W12_3430_USB1HS_PHY_DATA1,
+       W11_3430_USB1HS_PHY_DATA2,
+       Y11_3430_USB1HS_PHY_DATA3,
+       W9_3430_USB1HS_PHY_DATA4,
+       Y12_3430_USB1HS_PHY_DATA5,
+       W8_3430_USB1HS_PHY_DATA6,
+       Y13_3430_USB1HS_PHY_DATA7,
+
+       /* PHY - HSUSB: 12-pin ULPI PHY: Port 2*/
+       AA8_3430_USB2HS_PHY_CLK,
+       AA10_3430_USB2HS_PHY_STP,
+       AA9_3430_USB2HS_PHY_DIR,
+       AB11_3430_USB2HS_PHY_NXT,
+       AB10_3430_USB2HS_PHY_DATA0,
+       AB9_3430_USB2HS_PHY_DATA1,
+       W3_3430_USB2HS_PHY_DATA2,
+       T4_3430_USB2HS_PHY_DATA3,
+       T3_3430_USB2HS_PHY_DATA4,
+       R3_3430_USB2HS_PHY_DATA5,
+       R4_3430_USB2HS_PHY_DATA6,
+       T2_3430_USB2HS_PHY_DATA7,
+
+
+       /* TLL - HSUSB: 12-pin TLL Port 1*/
+       Y8_3430_USB1HS_TLL_CLK,
+       Y9_3430_USB1HS_TLL_STP,
+       AA14_3430_USB1HS_TLL_DIR,
+       AA11_3430_USB1HS_TLL_NXT,
+       W13_3430_USB1HS_TLL_DATA0,
+       W12_3430_USB1HS_TLL_DATA1,
+       W11_3430_USB1HS_TLL_DATA2,
+       Y11_3430_USB1HS_TLL_DATA3,
+       W9_3430_USB1HS_TLL_DATA4,
+       Y12_3430_USB1HS_TLL_DATA5,
+       W8_3430_USB1HS_TLL_DATA6,
+       Y13_3430_USB1HS_TLL_DATA7,
+
+       /* TLL - HSUSB: 12-pin TLL Port 2*/
+       AA8_3430_USB2HS_TLL_CLK,
+       AA10_3430_USB2HS_TLL_STP,
+       AA9_3430_USB2HS_TLL_DIR,
+       AB11_3430_USB2HS_TLL_NXT,
+       AB10_3430_USB2HS_TLL_DATA0,
+       AB9_3430_USB2HS_TLL_DATA1,
+       W3_3430_USB2HS_TLL_DATA2,
+       T4_3430_USB2HS_TLL_DATA3,
+       T3_3430_USB2HS_TLL_DATA4,
+       R3_3430_USB2HS_TLL_DATA5,
+       R4_3430_USB2HS_TLL_DATA6,
+       T2_3430_USB2HS_TLL_DATA7,
+
+       /* TLL - HSUSB: 12-pin TLL Port 3*/
+       AA6_3430_USB3HS_TLL_CLK,
+       AB3_3430_USB3HS_TLL_STP,
+       AA3_3430_USB3HS_TLL_DIR,
+       Y3_3430_USB3HS_TLL_NXT,
+       AA5_3430_USB3HS_TLL_DATA0,
+       Y4_3430_USB3HS_TLL_DATA1,
+       Y5_3430_USB3HS_TLL_DATA2,
+       W5_3430_USB3HS_TLL_DATA3,
+       AB12_3430_USB3HS_TLL_DATA4,
+       AB13_3430_USB3HS_TLL_DATA5,
+       AA13_3430_USB3HS_TLL_DATA6,
+       AA12_3430_USB3HS_TLL_DATA7,
+
+       /* PHY FSUSB: FS Serial for Port 1 (multiple PHY modes supported) */
+       AF10_3430_USB1FS_PHY_MM1_RXDP,
+       AG9_3430_USB1FS_PHY_MM1_RXDM,
+       W13_3430_USB1FS_PHY_MM1_RXRCV,
+       W12_3430_USB1FS_PHY_MM1_TXSE0,
+       W11_3430_USB1FS_PHY_MM1_TXDAT,
+       Y11_3430_USB1FS_PHY_MM1_TXEN_N,
+
+       /* PHY FSUSB: FS Serial for Port 2 (multiple PHY modes supported) */
+       AF7_3430_USB2FS_PHY_MM2_RXDP,
+       AH7_3430_USB2FS_PHY_MM2_RXDM,
+       AB10_3430_USB2FS_PHY_MM2_RXRCV,
+       AB9_3430_USB2FS_PHY_MM2_TXSE0,
+       W3_3430_USB2FS_PHY_MM2_TXDAT,
+       T4_3430_USB2FS_PHY_MM2_TXEN_N,
+
+       /* PHY FSUSB: FS Serial for Port 3 (multiple PHY modes supported) */
+       AH3_3430_USB3FS_PHY_MM3_RXDP,
+       AE3_3430_USB3FS_PHY_MM3_RXDM,
+       AD1_3430_USB3FS_PHY_MM3_RXRCV,
+       AE1_3430_USB3FS_PHY_MM3_TXSE0,
+       AD2_3430_USB3FS_PHY_MM3_TXDAT,
+       AC1_3430_USB3FS_PHY_MM3_TXEN_N,
+
+       /* 34xx GPIO
+        *  - normally these are bidirectional, no internal pullup/pulldown
+        *  - "_UP" suffix (GPIO3_UP) if internal pullup is configured
+        *  - "_DOWN" suffix (GPIO3_DOWN) with internal pulldown
+        *  - "_OUT" suffix (GPIO3_OUT) for output-only pins (unlike 24xx)
+        */
+       AH8_34XX_GPIO29,
+       J25_34XX_GPIO170,
+};
+
 struct omap_mux_cfg {
        struct pin_config       *pins;
        unsigned long           size;
index bdf30a0f87f2f2c81a0477bfff20a38a714b78c8..b0341e7a0cfa412affe303f4929a10b389eaf75b 100644 (file)
 #include <sound/pcm.h>
 #include <mach/mcbsp.h>
 #include <linux/platform_device.h>
+/*
+ * Debug functions
+ */
+#undef DEBUG
+/* #define DEBUG */
+
+#define ERR(ARGS...)                                           \
+       do {                                                    \
+               printk(KERN_ERR "{%s}-ERROR: ", __func__);      \
+               printk(ARGS);                                   \
+       } while (0)
+
+#ifdef DEBUG
+#define DPRINTK(ARGS...)                                       \
+       do {                                                    \
+               printk(KERN_INFO "<%s>: ", __func__);           \
+               printk(ARGS);                                   \
+       } while (0)
+#define ADEBUG() printk("XXX Alsa debug f:%s, l:%d\n", __func__, __LINE__)
+#define FN_IN printk(KERN_INFO "[%s]: start\n", __func__)
+#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n", __func__, n)
+#else
+#define DPRINTK(ARGS...)       /* nop */
+#define ADEBUG()               /* nop */
+#define FN_IN                  /* nop */
+#define FN_OUT(n)              /* nop */
+#endif
 
 #define DMA_BUF_SIZE   (1024 * 8)
 
@@ -62,12 +89,12 @@ struct audio_stream {
        char dma_q_count;       /* DMA Channel Q Count */
        int active:1;           /* we are using this stream for transfer now */
        int period;             /* current transfer period */
-       int periods;            /* current count of periods registerd in the DMA engine */
+       int periods;            /* current registered periods in DMA engine */
        spinlock_t dma_lock;    /* for locking in DMA operations */
        struct snd_pcm_substream *stream;       /* the pcm stream */
        unsigned linked:1;      /* dma channels linked */
-       int offset;             /* store start position of the last period in the alsa buffer */
-       int (*hw_start)(void);  /* interface to start HW interface, e.g. McBSP */
+       int offset;             /* start position of last period in alsa buf */
+       int (*hw_start)(void);  /* interface to start HW interface, (McBSP) */
        int (*hw_stop)(void);   /* interface to stop HW interface, e.g. McBSP */
 };
 
@@ -108,7 +135,8 @@ void snd_omap_suspend_mixer(void);
 void snd_omap_resume_mixer(void);
 #endif
 
-int snd_omap_alsa_post_probe(struct platform_device *pdev, struct omap_alsa_codec_config *config);
+int snd_omap_alsa_post_probe(struct platform_device *pdev,
+                               struct omap_alsa_codec_config *config);
 int snd_omap_alsa_remove(struct platform_device *pdev);
 #ifdef CONFIG_PM
 int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state);
index 505a38af8b22a36376c65e2374cf7b13d8f42361..d240046681381e071f98f1187d425b119e7b7594 100644 (file)
@@ -44,5 +44,7 @@
 #define OMAP1510_DSPREG_SIZE   SZ_128K
 #define OMAP1510_DSPREG_START  0xE1000000
 
+#define OMAP1510_DSP_MMU_BASE  (0xfffed200)
+
 #endif /*  __ASM_ARCH_OMAP15XX_H */
 
index c6c93afb2788f4b00911a67ec6d538570ec4a7ca..0e69b504c25fa1231a0fc1bd0f800432b50c57c2 100644 (file)
 #define OMAP16XX_DSPREG_SIZE   SZ_128K
 #define OMAP16XX_DSPREG_START  0xE1000000
 
+#define OMAP16XX_SEC_BASE      0xFFFE4000
+#define OMAP16XX_SEC_DES       (OMAP16XX_SEC_BASE + 0x0000)
+#define OMAP16XX_SEC_SHA1MD5   (OMAP16XX_SEC_BASE + 0x0800)
+#define OMAP16XX_SEC_RNG       (OMAP16XX_SEC_BASE + 0x1000)
+
 /*
  * ---------------------------------------------------------------------------
  * Interrupts
 #define WSPR_DISABLE_0         (0x0000aaaa)
 #define WSPR_DISABLE_1         (0x00005555)
 
-/* Mailbox */
+#define OMAP16XX_DSP_MMU_BASE  (0xfffed200)
 #define OMAP16XX_MAILBOX_BASE  (0xfffcf000)
 
 #endif /*  __ASM_ARCH_OMAP16XX_H */
index bb8319d66e9f5afa64a2798ccaca93ee98e76d57..c985c422a3750fdef03316903c39fa68494fb8f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/omap24xx.h
+ * include/asm-arm/arch-omap/omap24xx.h
  *
  * This file contains the processor specific definitions
  * of the TI OMAP24XX.
@@ -39,7 +39,6 @@
 /* interrupt controller */
 #define OMAP24XX_IC_BASE       (L4_24XX_BASE + 0xfe000)
 #define OMAP24XX_IVA_INTC_BASE 0x40000000
-#define IRQ_SIR_IRQ            0x0040
 
 #define OMAP2420_CTRL_BASE     L4_24XX_BASE
 #define OMAP2420_32KSYNCT_BASE (L4_24XX_BASE + 0x4000)
@@ -48,6 +47,7 @@
 #define OMAP2420_PRM_BASE      OMAP2420_CM_BASE
 #define OMAP2420_SDRC_BASE     (L3_24XX_BASE + 0x9000)
 #define OMAP2420_SMS_BASE      0x68008000
+#define OMAP2420_GPMC_BASE     0x6800a000
 
 #define OMAP2430_32KSYNCT_BASE (L4_WK_243X_BASE + 0x20000)
 #define OMAP2430_PRCM_BASE     (L4_WK_243X_BASE + 0x6000)
index 8e0479fff05a286090a092ccd80601a2fa5ede8a..4fb355657cfa2b7616c07fd7621998b6df395878 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/omap34xx.h
+ * include/asm-arm/arch-omap/omap34xx.h
  *
  * This file contains the processor specific definitions of the TI OMAP34XX.
  *
@@ -53,6 +53,8 @@
 #define OMAP34XX_HSUSB_OTG_BASE        (L4_34XX_BASE + 0xAB000)
 #define OMAP34XX_HSUSB_HOST_BASE       (L4_34XX_BASE + 0x64000)
 #define OMAP34XX_USBTLL_BASE   (L4_34XX_BASE + 0x62000)
+#define OMAP34XX_SR1_BASE      0x480C9000
+#define OMAP34XX_SR2_BASE      0x480CB000
 
 
 #if defined(CONFIG_ARCH_OMAP3430)
@@ -61,6 +63,7 @@
 #define OMAP2_CM_BASE                  OMAP3430_CM_BASE
 #define OMAP2_PRM_BASE                 OMAP3430_PRM_BASE
 #define OMAP2_VA_IC_BASE               IO_ADDRESS(OMAP34XX_IC_BASE)
+#define OMAP34XX_CAMERA_BASE           (L4_34XX_BASE + 0xBC000)
 
 #endif
 
index cae037d130792a7c466a697d079b475c2f756e8b..a4a84f357f264ccf90ea93fe32826e6b3e5b1635 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * File: arch/arm/plat-omap/include/mach/omapfb.h
+ * File: include/asm-arm/arch-omap/omapfb.h
  *
  * Framebuffer driver for TI OMAP boards
  *
@@ -62,6 +62,7 @@
 #define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE        0x00010000
 #define OMAPFB_CAPS_WINDOW_SCALE       0x00020000
 #define OMAPFB_CAPS_WINDOW_OVERLAY     0x00040000
+#define OMAPFB_CAPS_WINDOW_ROTATE      0x00080000
 #define OMAPFB_CAPS_SET_BACKLIGHT      0x01000000
 
 /* Values from DSP must map to lower 16-bits */
@@ -305,6 +306,7 @@ struct lcd_ctrl {
                                           int screen_width,
                                           int pos_x, int pos_y, int width,
                                           int height, int color_mode);
+       int             (*set_rotate)     (int angle);
        int             (*setup_mem)      (int plane, size_t size,
                                           int mem_type, unsigned long *paddr);
        int             (*mmap)           (struct fb_info *info,
@@ -374,6 +376,7 @@ extern struct lcd_ctrl omap1_lcd_ctrl;
 extern struct lcd_ctrl omap2_disp_ctrl;
 #endif
 
+extern void omapfb_reserve_sdram(void);
 extern void omapfb_register_panel(struct lcd_panel *panel);
 extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
 extern void omapfb_notify_clients(struct omapfb_device *fbdev,
index d57f20226b28733743c35455bb798836ba34f299..e30237117b69b75332e9b2d1cf00c963ed72cc72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * arch/arm/plat-omap/include/mach/onenand.h
+ * include/asm-arm/arch-omap/onenand.h
  *
  * Copyright (C) 2006 Nokia Corporation
  * Author: Juha Yrjola
@@ -16,6 +16,11 @@ struct omap_onenand_platform_data {
        int                     gpio_irq;
        struct mtd_partition    *parts;
        int                     nr_parts;
-       int                     (*onenand_setup)(void __iomem *);
+       int                     (*onenand_setup)(void __iomem *, int freq);
        int                     dma_channel;
 };
+
+int omap2_onenand_rephase(void);
+
+#define ONENAND_MAX_PARTITIONS 8
+
index bfa09325a5ffad992a7c2aadd05b84d899ccf36d..e4cf1c5b370a10df8022ee3e95aabb2f20ba0494 100644 (file)
  * Register and offset definitions to be used in PM assembler code
  * ----------------------------------------------------------------------------
  */
-#define CLKGEN_REG_ASM_BASE            io_p2v(0xfffece00)
+#define CLKGEN_REG_ASM_BASE            IO_ADDRESS(0xfffece00)
 #define ARM_IDLECT1_ASM_OFFSET         0x04
 #define ARM_IDLECT2_ASM_OFFSET         0x08
 
-#define TCMIF_ASM_BASE                 io_p2v(0xfffecc00)
+#define TCMIF_ASM_BASE                 IO_ADDRESS(0xfffecc00)
 #define EMIFS_CONFIG_ASM_OFFSET                0x0c
 #define EMIFF_SDRAM_CONFIG_ASM_OFFSET  0x20
 
 #if     !defined(CONFIG_ARCH_OMAP730) && \
        !defined(CONFIG_ARCH_OMAP15XX) && \
        !defined(CONFIG_ARCH_OMAP16XX) && \
-       !defined(CONFIG_ARCH_OMAP24XX)
+       !defined(CONFIG_ARCH_OMAP24XX) && \
+       !defined(CONFIG_ARCH_OMAP34XX)
 #error "Power management for this processor not implemented yet"
 #endif
 
 
 #include <linux/clk.h>
 
+extern struct kset power_subsys;
+
 extern void prevent_idle_sleep(void);
 extern void allow_idle_sleep(void);
 
@@ -132,10 +135,19 @@ void clk_deny_idle(struct clk *clk);
 
 extern void omap_pm_idle(void);
 extern void omap_pm_suspend(void);
+#ifdef CONFIG_PM
+extern void omap2_block_sleep(void);
+extern void omap2_allow_sleep(void);
+#else
+static inline void omap2_block_sleep(void) { }
+static inline void omap2_allow_sleep(void) { }
+#endif
 extern void omap730_cpu_suspend(unsigned short, unsigned short);
 extern void omap1510_cpu_suspend(unsigned short, unsigned short);
 extern void omap1610_cpu_suspend(unsigned short, unsigned short);
-extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision);
+extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
+                                       void __iomem *sdrc_power);
+extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
 extern void omap730_idle_loop_suspend(void);
 extern void omap1510_idle_loop_suspend(void);
 extern void omap1610_idle_loop_suspend(void);
@@ -145,10 +157,12 @@ extern unsigned int omap730_cpu_suspend_sz;
 extern unsigned int omap1510_cpu_suspend_sz;
 extern unsigned int omap1610_cpu_suspend_sz;
 extern unsigned int omap24xx_cpu_suspend_sz;
+extern unsigned int omap34xx_cpu_suspend_sz;
 extern unsigned int omap730_idle_loop_suspend_sz;
 extern unsigned int omap1510_idle_loop_suspend_sz;
 extern unsigned int omap1610_idle_loop_suspend_sz;
 extern unsigned int omap24xx_idle_loop_suspend_sz;
+extern unsigned int omap34xx_suspend_sz;
 
 #ifdef CONFIG_OMAP_SERIAL_WAKE
 extern void omap_serial_wake_trigger(int enable);
@@ -181,10 +195,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 +304,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 */
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
new file mode 100644 (file)
index 0000000..69c9e67
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * OMAP2/3 powerdomain control
+ *
+ * Copyright (C) 2007-8 Texas Instruments, Inc.
+ * Copyright (C) 2007-8 Nokia Corporation
+ *
+ * Written by Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef ASM_ARM_ARCH_OMAP_POWERDOMAIN
+#define ASM_ARM_ARCH_OMAP_POWERDOMAIN
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <asm/atomic.h>
+
+#include <mach/cpu.h>
+
+
+/* Powerdomain basic power states */
+#define PWRDM_POWER_OFF                0x0
+#define PWRDM_POWER_RET                0x1
+#define PWRDM_POWER_INACTIVE   0x2
+#define PWRDM_POWER_ON         0x3
+
+/* Powerdomain allowable state bitfields */
+#define PWRSTS_OFF_ON          ((1 << PWRDM_POWER_OFF) | \
+                                (1 << PWRDM_POWER_ON))
+
+#define PWRSTS_OFF_RET         ((1 << PWRDM_POWER_OFF) | \
+                                (1 << PWRDM_POWER_RET))
+
+#define PWRSTS_OFF_RET_ON      (PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
+
+
+/* Powerdomain flags */
+#define PWRDM_HAS_HDWR_SAR     (1 << 0) /* hardware save-and-restore support */
+
+
+/*
+ * Number of memory banks that are power-controllable. On OMAP3430, the
+ * maximum is 4.
+ */
+#define PWRDM_MAX_MEM_BANKS    4
+
+/*
+ * Maximum number of clockdomains that can be associated with a powerdomain.
+ * CORE powerdomain on OMAP3 is the worst case
+ */
+#define PWRDM_MAX_CLKDMS       4
+
+/* XXX A completely arbitrary number. What is reasonable here? */
+#define PWRDM_TRANSITION_BAILOUT 100000
+
+struct clockdomain;
+struct powerdomain;
+
+/* Encodes dependencies between powerdomains - statically defined */
+struct pwrdm_dep {
+
+       /* Powerdomain name */
+       const char *pwrdm_name;
+
+       /* Powerdomain pointer - resolved by the powerdomain code */
+       struct powerdomain *pwrdm;
+
+       /* Flags to mark OMAP chip restrictions, etc. */
+       const struct omap_chip_id omap_chip;
+
+};
+
+struct powerdomain {
+
+       /* Powerdomain name */
+       const char *name;
+
+       /* the address offset from CM_BASE/PRM_BASE */
+       const s16 prcm_offs;
+
+       /* Used to represent the OMAP chip types containing this pwrdm */
+       const struct omap_chip_id omap_chip;
+
+       /* Bit shift of this powerdomain's PM_WKDEP/CM_SLEEPDEP bit */
+       const u8 dep_bit;
+
+       /* Powerdomains that can be told to wake this powerdomain up */
+       struct pwrdm_dep *wkdep_srcs;
+
+       /* Powerdomains that can be told to keep this pwrdm from inactivity */
+       struct pwrdm_dep *sleepdep_srcs;
+
+       /* Possible powerdomain power states */
+       const u8 pwrsts;
+
+       /* Possible logic power states when pwrdm in RETENTION */
+       const u8 pwrsts_logic_ret;
+
+       /* Powerdomain flags */
+       const u8 flags;
+
+       /* Number of software-controllable memory banks in this powerdomain */
+       const u8 banks;
+
+       /* Possible memory bank pwrstates when pwrdm in RETENTION */
+       const u8 pwrsts_mem_ret[PWRDM_MAX_MEM_BANKS];
+
+       /* Possible memory bank pwrstates when pwrdm is ON */
+       const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS];
+
+       /* Clockdomains in this powerdomain */
+       struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS];
+
+       struct list_head node;
+
+};
+
+
+void pwrdm_init(struct powerdomain **pwrdm_list);
+
+int pwrdm_register(struct powerdomain *pwrdm);
+int pwrdm_unregister(struct powerdomain *pwrdm);
+struct powerdomain *pwrdm_lookup(const char *name);
+
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm));
+
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
+int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
+                        int (*fn)(struct powerdomain *pwrdm,
+                                  struct clockdomain *clkdm));
+
+int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_add_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_del_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+int pwrdm_read_sleepdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
+
+int pwrdm_get_mem_bank_count(struct powerdomain *pwrdm);
+
+int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_pwrst(struct powerdomain *pwrdm);
+int pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm);
+
+int pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst);
+int pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+int pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank, u8 pwrst);
+
+int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+
+int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
+int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
+bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
+
+int pwrdm_wait_transition(struct powerdomain *pwrdm);
+
+#endif
index 56eba0fd6f6a3db715397622a14009736158afd7..80dddcb970cfdd5e143d1ca46e3553cc9c890a72 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
-#ifndef __ASM_ARM_ARCH_DPM_PRCM_H
-#define __ASM_ARM_ARCH_DPM_PRCM_H
+#ifndef __ASM_ARM_ARCH_OMAP_PRCM_H
+#define __ASM_ARM_ARCH_OMAP_PRCM_H
 
 u32 omap_prcm_get_reset_sources(void);
+void omap_prcm_arch_reset(char mode);
+
+void cm_write_mod_reg(u32 val, s16 module, u16 idx);
+u32 cm_read_mod_reg(s16 module, u16 idx);
+u32 cm_rmw_mod_reg_bits(u32 mask, u32 bits, s16 module, s16 idx);
 
 #endif
 
index 787b7acec546eeaf7330be8e8e834b83e5b22d61..c66c838879037aa3a5b8b3f49796340373f4ac99 100644 (file)
@@ -4,10 +4,12 @@
 /*
  * OMAP2/3 SDRC/SMS register definitions
  *
- * Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (C) 2007 Nokia Corporation
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ * Copyright (C) 2007-2008 Nokia Corporation
  *
- * Written by Paul Walmsley
+ * Tony Lindgren
+ * Paul Walmsley
+ * Richard Woodruff
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 /* SDRC register offsets - read/write with sdrc_{read,write}_reg() */
 
 #define SDRC_SYSCONFIG         0x010
+#define SDRC_CS_CFG            0x040
+#define SDRC_SHARING           0x044
+#define SDRC_ERR_TYPE          0x04C
 #define SDRC_DLLA_CTRL         0x060
 #define SDRC_DLLA_STATUS       0x064
 #define SDRC_DLLB_CTRL         0x068
 #define SDRC_DLLB_STATUS       0x06C
 #define SDRC_POWER             0x070
+#define SDRC_MCFG_0            0x080
 #define SDRC_MR_0              0x084
+#define SDRC_ACTIM_CTRL_A_0    0x09c
+#define SDRC_ACTIM_CTRL_B_0    0x0a0
 #define SDRC_RFR_CTRL_0                0x0a4
+#define SDRC_MCFG_1            0x0B0
+#define SDRC_MR_1              0x0B4
+#define SDRC_ACTIM_CTRL_A_1    0x0C4
+#define SDRC_ACTIM_CTRL_B_1    0x0C8
+#define SDRC_RFR_CTRL_1                0x0D4
 
 /*
  * These values represent the number of memory clock cycles between
  * SMS register access
  */
 
-
-#define OMAP242X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP2420_SMS_BASE + reg)
-#define OMAP243X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP243X_SMS_BASE + reg)
-#define OMAP343X_SMS_REGADDR(reg)      (void __iomem *)IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#define OMAP242X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP2420_SMS_BASE + reg)
+#define OMAP243X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+#define OMAP343X_SMS_REGADDR(reg)      IO_ADDRESS(OMAP343X_SMS_BASE + reg)
 
 /* SMS register offsets - read/write with sms_{read,write}_reg() */
 
 #define SMS_SYSCONFIG          0x010
 /* REVISIT: fill in other SMS registers here */
 
+
+#ifndef __ASSEMBLER__
+
+/**
+ * struct omap_sdrc_params - SDRC parameters for a given SDRC clock rate
+ * @rate: SDRC clock rate (in Hz)
+ * @actim_ctrla: Value to program to SDRC_ACTIM_CTRLA for this rate
+ * @actim_ctrlb: Value to program to SDRC_ACTIM_CTRLB for this rate
+ * @rfr_ctrl: Value to program to SDRC_RFR_CTRL for this rate
+ * @mr: Value to program to SDRC_MR for this rate
+ *
+ * This structure holds a pre-computed set of register values for the
+ * SDRC for a given SDRC clock rate and SDRAM chip.  These are
+ * intended to be pre-computed and specified in an array in the board-*.c
+ * files.  The structure is keyed off the 'rate' field.
+ */
+struct omap_sdrc_params {
+       unsigned long rate;
+       u32 actim_ctrla;
+       u32 actim_ctrlb;
+       u32 rfr_ctrl;
+       u32 mr;
+};
+
+void __init omap2_sdrc_init(struct omap_sdrc_params *);
+struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r);
+
+#ifdef CONFIG_ARCH_OMAP2
+
+struct memory_timings {
+       u32 m_type;             /* ddr = 1, sdr = 0 */
+       u32 dll_mode;           /* use lock mode = 1, unlock mode = 0 */
+       u32 slow_dll_ctrl;      /* unlock mode, dll value for slow speed */
+       u32 fast_dll_ctrl;      /* unlock mode, dll value for fast speed */
+       u32 base_cs;            /* base chip select to use for calculations */
+};
+
+extern void omap2xxx_sdrc_init_params(u32 force_lock_to_unlock_mode);
+
+u32 omap2xxx_sdrc_dll_is_unlocked(void);
+u32 omap2xxx_sdrc_reprogram(u32 level, u32 force);
+
+#endif  /* CONFIG_ARCH_OMAP2 */
+
+#endif  /* __ASSEMBLER__ */
+
 #endif
index cc6bfa51ccb54022498cd8f02f1d68aa433467f0..8a676a04be481b1630cb7d0fa61cc87b00498aa4 100644 (file)
 #define OMAP_UART1_BASE                0x4806a000
 #define OMAP_UART2_BASE                0x4806c000
 #define OMAP_UART3_BASE                0x4806e000
+#elif defined(CONFIG_ARCH_OMAP3)
+/* OMAP3 serial ports */
+#define OMAP_UART1_BASE                0x4806a000
+#define OMAP_UART2_BASE                0x4806c000
+#define OMAP_UART3_BASE                0x49020000
 #endif
 
 #define OMAP_MAX_NR_PORTS      3
 #define OMAP1510_BASE_BAUD     (12000000/16)
 #define OMAP16XX_BASE_BAUD     (48000000/16)
+#define OMAP24XX_BASE_BAUD     (48000000/16)
 
-#define is_omap_port(p       ({int __ret = 0;                        \
-                       if (p == IO_ADDRESS(OMAP_UART1_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART2_BASE) || \
-                           p == IO_ADDRESS(OMAP_UART3_BASE))   \
-                               __ret = 1;                      \
-                       __ret;                                  \
+#define is_omap_port(pt)       ({int __ret = 0;                        \
+                       if ((pt)->port.mapbase == OMAP_UART1_BASE ||    \
+                           (pt)->port.mapbase == OMAP_UART2_BASE ||    \
+                           (pt)->port.mapbase == OMAP_UART3_BASE)      \
+                               __ret = 1;                              \
+                       __ret;                                          \
                        })
 
 #endif
index e09323449981aa230f4b1a6e309d2117878cd548..ab35d622dcf5c4553c6340da777146c89f3b974b 100644 (file)
@@ -21,6 +21,10 @@ 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 u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl,
+                                    u32 sdrc_actim_ctrla,
+                                    u32 sdrc_actim_ctrlb, u32 m2);
+
 /* Do not use these */
 extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
 extern unsigned long omap1_sram_reprogram_clock_sz;
@@ -53,4 +57,10 @@ extern void omap243x_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
                                                u32 mem_type);
 extern unsigned long omap243x_sram_reprogram_sdrc_sz;
 
+
+extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl,
+                                         u32 sdrc_actim_ctrla,
+                                         u32 sdrc_actim_ctrlb, u32 m2);
+extern unsigned long omap3_sram_configure_core_dpll_sz;
+
 #endif
diff --git a/arch/arm/plat-omap/include/mach/sti.h b/arch/arm/plat-omap/include/mach/sti.h
new file mode 100644 (file)
index 0000000..af43917
--- /dev/null
@@ -0,0 +1,172 @@
+#ifndef __ASM_ARCH_OMAP_STI_H
+#define __ASM_ARCH_OMAP_STI_H
+
+#include <asm/io.h>
+
+/*
+ * STI/SDTI
+ */
+#define STI_REVISION           0x00
+#define STI_SYSCONFIG          0x10
+#define STI_SYSSTATUS          0x14
+#define STI_IRQSTATUS          0x18
+#define STI_IRQSETEN           0x1c
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define STI_IRQCLREN           0x20
+#define STI_ER                 0x24
+#define STI_DR                 0x28
+#define STI_RX_DR              0x2c
+#define STI_RX_STATUS          0x30
+#define STI_CLK_CTRL           0x34
+#define STI_IOBOTT0            0x4c
+#define STI_IOTOP0             0x50
+#define STI_IOBOTT1            0x54
+#define STI_IOTOP1             0x58
+#define STI_SERIAL_CFG         0x60
+
+#define STI_OCPT2_MATCH_INT    0
+#define STI_OCPT1_MATCH_INT    1
+#define STI_EMIFS_MATCH_INT    2
+#define STI_EMIFF_MATCH_INT    3
+#define STI_IO_MATCH_INT       4
+#define STI_RX_INT             5
+#define STI_DUMP_REQUEST_INT   6
+#define STI_DUMP_UNDERRUN_INT  7
+#define STI_WAKEUP_INT         9
+
+#define STI_NR_IRQS    10
+
+#define STI_IRQSTATUS_MASK     0x2ff
+
+#define STI_RXFIFO_EMPTY       (1 << 0)
+
+/*
+ * We use the following enums to retain consistency with the STI "functional"
+ * specification.
+ */
+
+/* STI_ER */
+enum {
+       UnlockStatMatch = (1 <<  2), /* Unlock status match event regs */
+       IOMPUStr1En1    = (1 <<  3), /* MPU IO match, strobe 1, window 1 */
+       IOMPUStr0En1    = (1 <<  4), /* MPU IO match, strobe 0, window 1 */
+       IOMPUStr1En0    = (1 <<  5), /* MPU IO match, strobe 1, window 0 */
+       IOMPUStr0En0    = (1 <<  6), /* MPU IO match, strobe 0, window 0 */
+       IODSPStr1En1    = (1 <<  7), /* DSP IO match, strobe 1, window 1 */
+       IODSPStr0En1    = (1 <<  8), /* DSP IO match, strobe 0, window 1 */
+       IODSPStr1En0    = (1 <<  9), /* DSP IO match, strobe 1, window 0 */
+       IODSPStr0En0    = (1 << 10), /* DSP IO match, strobe 0, window 0 */
+       MemMatchEn      = (1 << 11), /* Memory matched event */
+       DSPCmdEn        = (1 << 12), /* DSP command write */
+       MPUCmdEn        = (1 << 13), /* MPU command write */
+       MemDumpEn       = (1 << 14), /* System memory dump */
+       STIEn           = (1 << 15), /* Global trace enable */
+};
+
+#define STI_PERCHANNEL_SIZE    4
+
+#define to_channel_address(channel) \
+       (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+#elif defined(CONFIG_ARCH_OMAP2)
+
+/* XTI interrupt bits */
+enum {
+       STI_WAKEUP_INT  = 0,
+       STI_ETB_THRESHOLD_INT,
+       STI_RX_INT,
+       STI_DUMP_REQUEST_INT,
+       STI_NR_IRQS,
+};
+
+/* XTI_TRACESELECT */
+enum {
+       CmdTimeStampEn  = (1 << 0),     /* Command write timestamps */
+       WinTimeStampEn  = (1 << 1),     /* Window match timestamps */
+       WinMatchEn      = (1 << 2),     /* Window match trace */
+       DSPCmdEn        = (1 << 3),     /* DSP command write */
+       MPUCmdEn        = (1 << 4),     /* MPU command write */
+       MemDumpEn0      = (1 << 5),     /* System memory dump */
+       MemDumpEn1      = (1 << 6),
+       MemDumpEn2      = (1 << 7),
+       ExtTriggerEn    = (1 << 8),     /* External trace trigger */
+       STIEn           = (1 << 9),     /* System trace enable */
+};
+
+#define STI_IRQSTATUS_MASK     0x0f
+#define STI_PERCHANNEL_SIZE    64
+
+/* XTI registers */
+#define XTI_SYSSTATUS          0x14
+#define XTI_TRACESELECT                0x24
+#define XTI_RXDATA             0x28
+#define XTI_SCLKCRTL           0x2c
+#define XTI_SCONFIG            0x30
+
+/* STI Compatability */
+#define STI_RX_STATUS          XTI_SYSSTATUS
+#define STI_IRQCLREN           STI_IRQSETEN
+#define STI_ER                 XTI_TRACESELECT
+#define STI_DR                 XTI_TRACESELECT
+#define STI_RX_DR              XTI_RXDATA
+#define STI_CLK_CTRL           XTI_SCLKCRTL
+#define STI_SERIAL_CFG         XTI_SCONFIG
+
+#define STI_RXFIFO_EMPTY       (1 << 8)
+
+#define to_channel_address(channel) \
+       (sti_channel_base + STI_PERCHANNEL_SIZE * (channel))
+
+#elif defined(CONFIG_ARCH_OMAP3)
+
+#define STI_PERCHANNEL_SIZE    0x1000
+#define to_channel_address(channel) \
+       (sti_channel_base + STI_PERCHANNEL_SIZE * (channel) + 0x800)
+
+#endif
+
+/* arch/arm/plat-omap/sti/sti.c */
+extern void __iomem *sti_base, *sti_channel_base;
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg);
+void sti_free_irq(unsigned int irq);
+void sti_enable_irq(unsigned int irq);
+void sti_disable_irq(unsigned int irq);
+void sti_ack_irq(unsigned int irq);
+
+int sti_trace_enable(int event);
+void sti_trace_disable(int event);
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel);
+
+/* arch/arm/plat-omap/sti/sti-fifo.c */
+int sti_read_packet(unsigned char *buf, int maxsize);
+
+static inline unsigned long sti_readl(unsigned long reg)
+{
+       return __raw_readl(sti_base + reg);
+}
+
+static inline void sti_writel(unsigned long data, unsigned long reg)
+{
+       __raw_writel(data, sti_base + reg);
+}
+
+static inline void sti_channel_writeb(unsigned char data, unsigned int channel)
+{
+       __raw_writeb(data, to_channel_address(channel));
+}
+
+static inline void sti_channel_writel(unsigned long data, unsigned int channel)
+{
+       __raw_writel(data, to_channel_address(channel));
+}
+
+#define STI_TRACE_CONTROL_CHANNEL      253
+
+static inline void sti_channel_flush(unsigned int channel)
+{
+       sti_channel_writeb(channel, STI_TRACE_CONTROL_CHANNEL);
+}
+#endif /* __ASM_ARCH_OMAP_STI_H */
index 06a28c7b98de7020054497fbfcb4714dec9ac321..61d9f36722a60db3085645080721a4f0791d0da0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copied from arch/arm/mach-sa1100/include/mach/system.h
+ * Copied from linux/include/asm-arm/arch-sa1100/system.h
  * Copyright (c) 1999 Nicolas Pitre <nico@cam.org>
  */
 #ifndef __ASM_ARCH_SYSTEM_H
@@ -9,12 +9,12 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 
+#include <mach/prcm.h>
+
 #ifndef CONFIG_MACH_VOICEBLUE
 #define voiceblue_reset()              do {} while (0)
 #endif
 
-extern void omap_prcm_arch_reset(char mode);
-
 static inline void arch_idle(void)
 {
        cpu_do_idle();
@@ -40,7 +40,7 @@ static inline void omap1_arch_reset(char mode)
 
 static inline void arch_reset(char mode)
 {
-       if (!cpu_is_omap24xx())
+       if (!cpu_class_is_omap2())
                omap1_arch_reset(mode);
        else
                omap_prcm_arch_reset(mode);
index 6d35767bc48f0f1ebb1e682ab46ead9f9d697e5c..b3f5ea96e056a31d5c203a4d09ad8d6ffd0b5512 100644 (file)
@@ -38,4 +38,6 @@
 #define CLOCK_TICK_RATE                (HZ * 100000UL)
 #endif
 
+extern struct sys_timer omap_timer;
+
 #endif /* __ASM_ARCH_OMAP_TIMEX_H */
diff --git a/arch/arm/plat-omap/include/mach/usb-ehci.h b/arch/arm/plat-omap/include/mach/usb-ehci.h
new file mode 100644 (file)
index 0000000..4419bd1
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-omap/include/mach/usb-ehci.h
+ *
+ * Hardware definitions for Synopsys EHCI host controller.
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_USB_EHCI_H
+#define __ASM_ARCH_OMAP_USB_EHCI_H
+
+extern void usb_ehci_init(void);
+
+#endif /* __ASM_ARCH_OMAP_USB_EHCI_H */
+
diff --git a/arch/arm/plat-omap/include/mach/usb-musb.h b/arch/arm/plat-omap/include/mach/usb-musb.h
new file mode 100644 (file)
index 0000000..b455b29
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/arm/plat-omap/include/mach/usb-musb.h
+ *
+ * Hardware definitions for Mentor Graphics MUSBMHDRC.
+ *
+ * Initial creation by Felipe Balbi.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_USB_MUSB_H
+#define __ASM_ARCH_OMAP_USB_MUSB_H
+
+extern void usb_musb_init(void);
+
+#endif /* __ASM_ARCH_OMAP_USB_MUSB_H */
+
index a56a610950c239e38e35b7f7d963084237f12fb4..e0781558d831b30f3db66e1033ad18d6d5b84766 100644 (file)
@@ -27,6 +27,9 @@
 #define UDC_BASE                       OMAP2_UDC_BASE
 #define OMAP_OHCI_BASE                 OMAP2_OHCI_BASE
 
+void __init usb_musb_init(void);
+void __init usb_ehci_init(void);
+
 #endif
 
 /*-------------------------------------------------------------------------*/
index dc104cd96197ce63e983cbd4139830bbe36ce29b..b97dfafeebda6179a5ef652fb0e8070a2ef4b3ae 100644 (file)
@@ -17,5 +17,5 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END      (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END      (PAGE_OFFSET + 0x18000000)
 
diff --git a/arch/arm/plat-omap/io.c b/arch/arm/plat-omap/io.c
new file mode 100644 (file)
index 0000000..af326ef
--- /dev/null
@@ -0,0 +1,107 @@
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
+#include <mach/omap730.h>
+#include <mach/omap1510.h>
+#include <mach/omap16xx.h>
+#include <mach/omap24xx.h>
+#include <mach/omap34xx.h>
+
+#define BETWEEN(p,st,sz)       ((p) >= (st) && (p) < ((st) + (sz)))
+#define XLATE(p,pst,vst)       ((void __iomem *)((p) - (pst) + (vst)))
+
+/*
+ * Intercept ioremap() requests for addresses in our fixed mapping regions.
+ */
+void __iomem *omap_ioremap(unsigned long p, size_t size, unsigned int type)
+{
+#ifdef CONFIG_ARCH_OMAP1
+       if (cpu_class_is_omap1()) {
+               if (BETWEEN(p, IO_PHYS, IO_SIZE))
+                       return XLATE(p, IO_PHYS, IO_VIRT);
+       }
+       if (cpu_is_omap730()) {
+               if (BETWEEN(p, OMAP730_DSP_BASE, OMAP730_DSP_SIZE))
+                       return XLATE(p, OMAP730_DSP_BASE, OMAP730_DSP_START);
+
+               if (BETWEEN(p, OMAP730_DSPREG_BASE, OMAP730_DSPREG_SIZE))
+                       return XLATE(p, OMAP730_DSPREG_BASE,
+                                       OMAP730_DSPREG_START);
+       }
+       if (cpu_is_omap15xx()) {
+               if (BETWEEN(p, OMAP1510_DSP_BASE, OMAP1510_DSP_SIZE))
+                       return XLATE(p, OMAP1510_DSP_BASE, OMAP1510_DSP_START);
+
+               if (BETWEEN(p, OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_SIZE))
+                       return XLATE(p, OMAP1510_DSPREG_BASE,
+                                       OMAP1510_DSPREG_START);
+       }
+       if (cpu_is_omap16xx()) {
+               if (BETWEEN(p, OMAP16XX_DSP_BASE, OMAP16XX_DSP_SIZE))
+                       return XLATE(p, OMAP16XX_DSP_BASE, OMAP16XX_DSP_START);
+
+               if (BETWEEN(p, OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_SIZE))
+                       return XLATE(p, OMAP16XX_DSPREG_BASE,
+                                       OMAP16XX_DSPREG_START);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP2
+       if (cpu_is_omap24xx()) {
+               if (BETWEEN(p, L3_24XX_PHYS, L3_24XX_SIZE))
+                       return XLATE(p, L3_24XX_PHYS, L3_24XX_VIRT);
+               if (BETWEEN(p, L4_24XX_PHYS, L4_24XX_SIZE))
+                       return XLATE(p, L4_24XX_PHYS, L4_24XX_VIRT);
+       }
+       if (cpu_is_omap2420()) {
+               if (BETWEEN(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_SIZE))
+                       return XLATE(p, DSP_MEM_24XX_PHYS, DSP_MEM_24XX_VIRT);
+               if (BETWEEN(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE))
+                       return XLATE(p, DSP_IPI_24XX_PHYS, DSP_IPI_24XX_SIZE);
+               if (BETWEEN(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_SIZE))
+                       return XLATE(p, DSP_MMU_24XX_PHYS, DSP_MMU_24XX_VIRT);
+       }
+       if (cpu_is_omap2430()) {
+               if (BETWEEN(p, L4_WK_243X_PHYS, L4_WK_243X_SIZE))
+                       return XLATE(p, L4_WK_243X_PHYS, L4_WK_243X_VIRT);
+               if (BETWEEN(p, OMAP243X_GPMC_PHYS, OMAP243X_GPMC_SIZE))
+                       return XLATE(p, OMAP243X_GPMC_PHYS, OMAP243X_GPMC_VIRT);
+               if (BETWEEN(p, OMAP243X_SDRC_PHYS, OMAP243X_SDRC_SIZE))
+                       return XLATE(p, OMAP243X_SDRC_PHYS, OMAP243X_SDRC_VIRT);
+               if (BETWEEN(p, OMAP243X_SMS_PHYS, OMAP243X_SMS_SIZE))
+                       return XLATE(p, OMAP243X_SMS_PHYS, OMAP243X_SMS_VIRT);
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP3
+       if (cpu_is_omap34xx()) {
+               if (BETWEEN(p, L3_34XX_PHYS, L3_34XX_SIZE))
+                       return XLATE(p, L3_34XX_PHYS, L3_34XX_VIRT);
+               if (BETWEEN(p, L4_34XX_PHYS, L4_34XX_SIZE))
+                       return XLATE(p, L4_34XX_PHYS, L4_34XX_VIRT);
+               if (BETWEEN(p, L4_WK_34XX_PHYS, L4_WK_34XX_SIZE))
+                       return XLATE(p, L4_WK_34XX_PHYS, L4_WK_34XX_VIRT);
+               if (BETWEEN(p, OMAP34XX_GPMC_PHYS, OMAP34XX_GPMC_SIZE))
+                       return XLATE(p, OMAP34XX_GPMC_PHYS, OMAP34XX_GPMC_VIRT);
+               if (BETWEEN(p, OMAP343X_SMS_PHYS, OMAP343X_SMS_SIZE))
+                       return XLATE(p, OMAP343X_SMS_PHYS, OMAP343X_SMS_VIRT);
+               if (BETWEEN(p, OMAP343X_SDRC_PHYS, OMAP343X_SDRC_SIZE))
+                       return XLATE(p, OMAP343X_SDRC_PHYS, OMAP343X_SDRC_VIRT);
+               if (BETWEEN(p, L4_PER_34XX_PHYS, L4_PER_34XX_SIZE))
+                       return XLATE(p, L4_PER_34XX_PHYS, L4_PER_34XX_VIRT);
+               if (BETWEEN(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_SIZE))
+                       return XLATE(p, L4_EMU_34XX_PHYS, L4_EMU_34XX_VIRT);
+       }
+#endif
+
+       return __arm_ioremap(p, size, type);
+}
+EXPORT_SYMBOL(omap_ioremap);
+
+void omap_iounmap(volatile void __iomem *addr)
+{
+       unsigned long virt = (unsigned long)addr;
+
+       if (virt >= VMALLOC_START && virt < VMALLOC_END)
+               __iounmap(addr);
+}
+EXPORT_SYMBOL(omap_iounmap);
index 014d26574bb61cd52267db7edfff9ad439e0c4bd..af33fc713e1a325d7e5179d8fa20921ebc1e152d 100644 (file)
 #include <mach/dma.h>
 #include <mach/mcbsp.h>
 
-static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+struct omap_mcbsp **mcbsp_ptr;
+int omap_mcbsp_count;
 
-#define omap_mcbsp_check_valid_id(id)  (mcbsp[id].pdata && \
-                                       mcbsp[id].pdata->ops && \
-                                       mcbsp[id].pdata->ops->check && \
-                                       (mcbsp[id].pdata->ops->check(id) == 0))
+void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val)
+{
+       if (cpu_class_is_omap1() || cpu_is_omap2420())
+               __raw_writew((u16)val, io_base + reg);
+       else
+               __raw_writel(val, io_base + reg);
+}
+
+int omap_mcbsp_read(void __iomem *io_base, u16 reg)
+{
+       if (cpu_class_is_omap1() || cpu_is_omap2420())
+               return __raw_readw(io_base + reg);
+       else
+               return __raw_readl(io_base + reg);
+}
+
+#define OMAP_MCBSP_READ(base, reg) \
+                       omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg)
+#define OMAP_MCBSP_WRITE(base, reg, val) \
+                       omap_mcbsp_write(base, OMAP_MCBSP_REG_##reg, val)
+
+#define omap_mcbsp_check_valid_id(id)  (id < omap_mcbsp_count)
+#define id_to_mcbsp_ptr(id)            mcbsp_ptr[id];
 
 static void omap_mcbsp_dump_reg(u8 id)
 {
-       dev_dbg(mcbsp[id].dev, "**** McBSP%d regs ****\n", mcbsp[id].id);
-       dev_dbg(mcbsp[id].dev, "DRR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
-       dev_dbg(mcbsp[id].dev, "DRR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
-       dev_dbg(mcbsp[id].dev, "DXR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
-       dev_dbg(mcbsp[id].dev, "DXR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
-       dev_dbg(mcbsp[id].dev, "SPCR2: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
-       dev_dbg(mcbsp[id].dev, "SPCR1: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
-       dev_dbg(mcbsp[id].dev, "RCR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
-       dev_dbg(mcbsp[id].dev, "RCR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
-       dev_dbg(mcbsp[id].dev, "XCR2:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
-       dev_dbg(mcbsp[id].dev, "XCR1:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
-       dev_dbg(mcbsp[id].dev, "SRGR2: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
-       dev_dbg(mcbsp[id].dev, "SRGR1: 0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
-       dev_dbg(mcbsp[id].dev, "PCR0:  0x%04x\n",
-                       OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
-       dev_dbg(mcbsp[id].dev, "***********************\n");
+       struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id);
+
+       dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id);
+       dev_dbg(mcbsp->dev, "DRR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DRR2));
+       dev_dbg(mcbsp->dev, "DRR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DRR1));
+       dev_dbg(mcbsp->dev, "DXR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DXR2));
+       dev_dbg(mcbsp->dev, "DXR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, DXR1));
+       dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SPCR2));
+       dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SPCR1));
+       dev_dbg(mcbsp->dev, "RCR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, RCR2));
+       dev_dbg(mcbsp->dev, "RCR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, RCR1));
+       dev_dbg(mcbsp->dev, "XCR2:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, XCR2));
+       dev_dbg(mcbsp->dev, "XCR1:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, XCR1));
+       dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SRGR2));
+       dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, SRGR1));
+       dev_dbg(mcbsp->dev, "PCR0:  0x%04x\n",
+                       OMAP_MCBSP_READ(mcbsp->io_base, PCR0));
+       dev_dbg(mcbsp->dev, "***********************\n");
 }
 
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
@@ -126,16 +148,18 @@ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
  */
 void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       io_base = mcbsp[id].io_base;
-       dev_dbg(mcbsp[id].dev, "Configuring McBSP%d  io_base: 0x%8x\n",
-                       mcbsp[id].id, io_base);
+       io_base = mcbsp->io_base;
+       dev_dbg(mcbsp->dev, "Configuring McBSP%d  phys_base: 0x%08lx\n",
+                       mcbsp->id, mcbsp->phys_base);
 
        /* We write the given config */
        OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
@@ -158,23 +182,26 @@ EXPORT_SYMBOL(omap_mcbsp_config);
  */
 int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type)
 {
+       struct omap_mcbsp *mcbsp;
+
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       spin_lock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
 
-       if (!mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d is currently in use\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       if (!mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return -EINVAL;
        }
 
-       mcbsp[id].io_type = io_type;
+       mcbsp->io_type = io_type;
 
-       spin_unlock(&mcbsp[id].lock);
+       spin_unlock(&mcbsp->lock);
 
        return 0;
 }
@@ -182,53 +209,60 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type);
 
 int omap_mcbsp_request(unsigned int id)
 {
+       struct omap_mcbsp *mcbsp;
        int err;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (mcbsp[id].pdata->ops->request)
-               mcbsp[id].pdata->ops->request(id);
+       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request)
+               mcbsp->pdata->ops->request(id);
 
-       clk_enable(mcbsp[id].clk);
+       clk_enable(mcbsp->clk);
 
-       spin_lock(&mcbsp[id].lock);
-       if (!mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d is currently in use\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
+       if (!mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d is currently in use\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return -1;
        }
 
-       mcbsp[id].free = 0;
-       spin_unlock(&mcbsp[id].lock);
+       mcbsp->free = 0;
+       spin_unlock(&mcbsp->lock);
+
+       /*
+        * Make sure that transmitter, receiver and sample-rate generator are
+        * not running before activating IRQs.
+        */
+       OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR1, 0);
+       OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR2, 0);
 
-       if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+       if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
                /* We need to get IRQs here */
-               err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler,
-                                       0, "McBSP", (void *) (&mcbsp[id]));
+               init_completion(&mcbsp->tx_irq_completion);
+               err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler,
+                                       0, "McBSP", (void *)mcbsp);
                if (err != 0) {
-                       dev_err(mcbsp[id].dev, "Unable to request TX IRQ %d "
-                                       "for McBSP%d\n", mcbsp[id].tx_irq,
-                                       mcbsp[id].id);
+                       dev_err(mcbsp->dev, "Unable to request TX IRQ %d "
+                                       "for McBSP%d\n", mcbsp->tx_irq,
+                                       mcbsp->id);
                        return err;
                }
 
-               init_completion(&(mcbsp[id].tx_irq_completion));
-
-               err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler,
-                                       0, "McBSP", (void *) (&mcbsp[id]));
+               init_completion(&mcbsp->rx_irq_completion);
+               err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler,
+                                       0, "McBSP", (void *)mcbsp);
                if (err != 0) {
-                       dev_err(mcbsp[id].dev, "Unable to request RX IRQ %d "
-                                       "for McBSP%d\n", mcbsp[id].rx_irq,
-                                       mcbsp[id].id);
-                       free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+                       dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
+                                       "for McBSP%d\n", mcbsp->rx_irq,
+                                       mcbsp->id);
+                       free_irq(mcbsp->tx_irq, (void *)mcbsp);
                        return err;
                }
-
-               init_completion(&(mcbsp[id].rx_irq_completion));
        }
 
        return 0;
@@ -237,31 +271,34 @@ EXPORT_SYMBOL(omap_mcbsp_request);
 
 void omap_mcbsp_free(unsigned int id)
 {
+       struct omap_mcbsp *mcbsp;
+
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (mcbsp[id].pdata->ops->free)
-               mcbsp[id].pdata->ops->free(id);
+       if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(id);
 
-       clk_disable(mcbsp[id].clk);
+       clk_disable(mcbsp->clk);
 
-       spin_lock(&mcbsp[id].lock);
-       if (mcbsp[id].free) {
-               dev_err(mcbsp[id].dev, "McBSP%d was not reserved\n",
-                       mcbsp[id].id);
-               spin_unlock(&mcbsp[id].lock);
+       spin_lock(&mcbsp->lock);
+       if (mcbsp->free) {
+               dev_err(mcbsp->dev, "McBSP%d was not reserved\n",
+                       mcbsp->id);
+               spin_unlock(&mcbsp->lock);
                return;
        }
 
-       mcbsp[id].free = 1;
-       spin_unlock(&mcbsp[id].lock);
+       mcbsp->free = 1;
+       spin_unlock(&mcbsp->lock);
 
-       if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) {
+       if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
                /* Free IRQs */
-               free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
-               free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+               free_irq(mcbsp->rx_irq, (void *)mcbsp);
+               free_irq(mcbsp->tx_irq, (void *)mcbsp);
        }
 }
 EXPORT_SYMBOL(omap_mcbsp_free);
@@ -273,18 +310,19 @@ EXPORT_SYMBOL(omap_mcbsp_free);
  */
 void omap_mcbsp_start(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 w;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
 
-       io_base = mcbsp[id].io_base;
-
-       mcbsp[id].rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
-       mcbsp[id].tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
+       mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
+       mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
 
        /* Start the sample generator */
        w = OMAP_MCBSP_READ(io_base, SPCR2);
@@ -310,7 +348,8 @@ EXPORT_SYMBOL(omap_mcbsp_start);
 
 void omap_mcbsp_stop(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 w;
 
        if (!omap_mcbsp_check_valid_id(id)) {
@@ -318,7 +357,8 @@ void omap_mcbsp_stop(unsigned int id)
                return;
        }
 
-       io_base = mcbsp[id].io_base;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
 
        /* Reset transmitter */
        w = OMAP_MCBSP_READ(io_base, SPCR2);
@@ -337,14 +377,17 @@ EXPORT_SYMBOL(omap_mcbsp_stop);
 /* polled mcbsp i/o operations */
 int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
 {
-       u32 base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
 
-       base = mcbsp[id].io_base;
+       mcbsp = id_to_mcbsp_ptr(id);
+       base = mcbsp->io_base;
+
        writew(buf, base + OMAP_MCBSP_REG_DXR1);
        /* if frame sync error - clear the error */
        if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {
@@ -366,8 +409,8 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
                                       (XRST),
                                       base + OMAP_MCBSP_REG_SPCR2);
                                udelay(10);
-                               dev_err(mcbsp[id].dev, "Could not write to"
-                                       " McBSP%d Register\n", mcbsp[id].id);
+                               dev_err(mcbsp->dev, "Could not write to"
+                                       " McBSP%d Register\n", mcbsp->id);
                                return -2;
                        }
                }
@@ -379,14 +422,16 @@ EXPORT_SYMBOL(omap_mcbsp_pollwrite);
 
 int omap_mcbsp_pollread(unsigned int id, u16 *buf)
 {
-       u32 base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *base;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       base = mcbsp[id].io_base;
+       base = mcbsp->io_base;
        /* if frame sync error - clear the error */
        if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) {
                /* clear error */
@@ -407,8 +452,8 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf)
                                       (RRST),
                                       base + OMAP_MCBSP_REG_SPCR1);
                                udelay(10);
-                               dev_err(mcbsp[id].dev, "Could not read from"
-                                       " McBSP%d Register\n", mcbsp[id].id);
+                               dev_err(mcbsp->dev, "Could not read from"
+                                       " McBSP%d Register\n", mcbsp->id);
                                return -2;
                        }
                }
@@ -424,7 +469,8 @@ EXPORT_SYMBOL(omap_mcbsp_pollread);
  */
 void omap_mcbsp_xmit_word(unsigned int id, u32 word)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        omap_mcbsp_word_length word_length;
 
        if (!omap_mcbsp_check_valid_id(id)) {
@@ -432,10 +478,11 @@ void omap_mcbsp_xmit_word(unsigned int id, u32 word)
                return;
        }
 
-       io_base = mcbsp[id].io_base;
-       word_length = mcbsp[id].tx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+       word_length = mcbsp->tx_word_length;
 
-       wait_for_completion(&(mcbsp[id].tx_irq_completion));
+       wait_for_completion(&mcbsp->tx_irq_completion);
 
        if (word_length > OMAP_MCBSP_WORD_16)
                OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
@@ -445,7 +492,8 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word);
 
 u32 omap_mcbsp_recv_word(unsigned int id)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        u16 word_lsb, word_msb = 0;
        omap_mcbsp_word_length word_length;
 
@@ -453,11 +501,12 @@ u32 omap_mcbsp_recv_word(unsigned int id)
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       word_length = mcbsp[id].rx_word_length;
-       io_base = mcbsp[id].io_base;
+       word_length = mcbsp->rx_word_length;
+       io_base = mcbsp->io_base;
 
-       wait_for_completion(&(mcbsp[id].rx_irq_completion));
+       wait_for_completion(&mcbsp->rx_irq_completion);
 
        if (word_length > OMAP_MCBSP_WORD_16)
                word_msb = OMAP_MCBSP_READ(io_base, DRR2);
@@ -469,7 +518,8 @@ EXPORT_SYMBOL(omap_mcbsp_recv_word);
 
 int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
 {
-       u32 io_base;
+       struct omap_mcbsp *mcbsp;
+       void __iomem *io_base;
        omap_mcbsp_word_length tx_word_length;
        omap_mcbsp_word_length rx_word_length;
        u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
@@ -478,10 +528,10 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
-
-       io_base = mcbsp[id].io_base;
-       tx_word_length = mcbsp[id].tx_word_length;
-       rx_word_length = mcbsp[id].rx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+       tx_word_length = mcbsp->tx_word_length;
+       rx_word_length = mcbsp->rx_word_length;
 
        if (tx_word_length != rx_word_length)
                return -EINVAL;
@@ -496,8 +546,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d transmitter not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d transmitter not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -517,8 +567,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d receiver not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d receiver not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -534,7 +584,9 @@ EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll);
 
 int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
 {
-       u32 io_base, clock_word = 0;
+       struct omap_mcbsp *mcbsp;
+       u32 clock_word = 0;
+       void __iomem *io_base;
        omap_mcbsp_word_length tx_word_length;
        omap_mcbsp_word_length rx_word_length;
        u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0;
@@ -544,9 +596,11 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                return -ENODEV;
        }
 
-       io_base = mcbsp[id].io_base;
-       tx_word_length = mcbsp[id].tx_word_length;
-       rx_word_length = mcbsp[id].rx_word_length;
+       mcbsp = id_to_mcbsp_ptr(id);
+       io_base = mcbsp->io_base;
+
+       tx_word_length = mcbsp->tx_word_length;
+       rx_word_length = mcbsp->rx_word_length;
 
        if (tx_word_length != rx_word_length)
                return -EINVAL;
@@ -561,8 +615,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d transmitter not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d transmitter not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -582,8 +636,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word)
                        udelay(10);
                        OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST);
                        udelay(10);
-                       dev_err(mcbsp[id].dev, "McBSP%d receiver not "
-                               "ready\n", mcbsp[id].id);
+                       dev_err(mcbsp->dev, "McBSP%d receiver not "
+                               "ready\n", mcbsp->id);
                        return -EAGAIN;
                }
        }
@@ -609,6 +663,7 @@ EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll);
 int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
                                unsigned int length)
 {
+       struct omap_mcbsp *mcbsp;
        int dma_tx_ch;
        int src_port = 0;
        int dest_port = 0;
@@ -618,50 +673,51 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer,
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX",
+       if (omap_request_dma(mcbsp->dma_tx_sync, "McBSP TX",
                                omap_mcbsp_tx_dma_callback,
-                               &mcbsp[id],
+                               mcbsp,
                                &dma_tx_ch)) {
-               dev_err(mcbsp[id].dev, " Unable to request DMA channel for "
+               dev_err(mcbsp->dev, " Unable to request DMA channel for "
                                "McBSP%d TX. Trying IRQ based TX\n",
-                               mcbsp[id].id);
+                               mcbsp->id);
                return -EAGAIN;
        }
-       mcbsp[id].dma_tx_lch = dma_tx_ch;
+       mcbsp->dma_tx_lch = dma_tx_ch;
 
-       dev_err(mcbsp[id].dev, "McBSP%d TX DMA on channel %d\n", mcbsp[id].id,
+       dev_err(mcbsp->dev, "McBSP%d TX DMA on channel %d\n", mcbsp->id,
                dma_tx_ch);
 
-       init_completion(&(mcbsp[id].tx_dma_completion));
+       init_completion(&mcbsp->tx_dma_completion);
 
        if (cpu_class_is_omap1()) {
                src_port = OMAP_DMA_PORT_TIPB;
                dest_port = OMAP_DMA_PORT_EMIFF;
        }
        if (cpu_class_is_omap2())
-               sync_dev = mcbsp[id].dma_tx_sync;
+               sync_dev = mcbsp->dma_tx_sync;
 
-       omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_transfer_params(mcbsp->dma_tx_lch,
                                     OMAP_DMA_DATA_TYPE_S16,
                                     length >> 1, 1,
                                     OMAP_DMA_SYNC_ELEMENT,
         sync_dev, 0);
 
-       omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_dest_params(mcbsp->dma_tx_lch,
                                 src_port,
                                 OMAP_DMA_AMODE_CONSTANT,
-                                mcbsp[id].phys_base + OMAP_MCBSP_REG_DXR1,
+                                mcbsp->phys_base + OMAP_MCBSP_REG_DXR1,
                                 0, 0);
 
-       omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
+       omap_set_dma_src_params(mcbsp->dma_tx_lch,
                                dest_port,
                                OMAP_DMA_AMODE_POST_INC,
                                buffer,
                                0, 0);
 
-       omap_start_dma(mcbsp[id].dma_tx_lch);
-       wait_for_completion(&(mcbsp[id].tx_dma_completion));
+       omap_start_dma(mcbsp->dma_tx_lch);
+       wait_for_completion(&mcbsp->tx_dma_completion);
 
        return 0;
 }
@@ -670,6 +726,7 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
 int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
                                unsigned int length)
 {
+       struct omap_mcbsp *mcbsp;
        int dma_rx_ch;
        int src_port = 0;
        int dest_port = 0;
@@ -679,50 +736,51 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer,
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return -ENODEV;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
-       if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX",
+       if (omap_request_dma(mcbsp->dma_rx_sync, "McBSP RX",
                                omap_mcbsp_rx_dma_callback,
-                               &mcbsp[id],
+                               mcbsp,
                                &dma_rx_ch)) {
-               dev_err(mcbsp[id].dev, "Unable to request DMA channel for "
+               dev_err(mcbsp->dev, "Unable to request DMA channel for "
                                "McBSP%d RX. Trying IRQ based RX\n",
-                               mcbsp[id].id);
+                               mcbsp->id);
                return -EAGAIN;
        }
-       mcbsp[id].dma_rx_lch = dma_rx_ch;
+       mcbsp->dma_rx_lch = dma_rx_ch;
 
-       dev_err(mcbsp[id].dev, "McBSP%d RX DMA on channel %d\n", mcbsp[id].id,
+       dev_err(mcbsp->dev, "McBSP%d RX DMA on channel %d\n", mcbsp->id,
                dma_rx_ch);
 
-       init_completion(&(mcbsp[id].rx_dma_completion));
+       init_completion(&mcbsp->rx_dma_completion);
 
        if (cpu_class_is_omap1()) {
                src_port = OMAP_DMA_PORT_TIPB;
                dest_port = OMAP_DMA_PORT_EMIFF;
        }
        if (cpu_class_is_omap2())
-               sync_dev = mcbsp[id].dma_rx_sync;
+               sync_dev = mcbsp->dma_rx_sync;
 
-       omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_transfer_params(mcbsp->dma_rx_lch,
                                        OMAP_DMA_DATA_TYPE_S16,
                                        length >> 1, 1,
                                        OMAP_DMA_SYNC_ELEMENT,
                                        sync_dev, 0);
 
-       omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_src_params(mcbsp->dma_rx_lch,
                                src_port,
                                OMAP_DMA_AMODE_CONSTANT,
-                               mcbsp[id].phys_base + OMAP_MCBSP_REG_DRR1,
+                               mcbsp->phys_base + OMAP_MCBSP_REG_DRR1,
                                0, 0);
 
-       omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+       omap_set_dma_dest_params(mcbsp->dma_rx_lch,
                                        dest_port,
                                        OMAP_DMA_AMODE_POST_INC,
                                        buffer,
                                        0, 0);
 
-       omap_start_dma(mcbsp[id].dma_rx_lch);
-       wait_for_completion(&(mcbsp[id].rx_dma_completion));
+       omap_start_dma(mcbsp->dma_rx_lch);
+       wait_for_completion(&mcbsp->rx_dma_completion);
 
        return 0;
 }
@@ -737,12 +795,14 @@ EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
 void omap_mcbsp_set_spi_mode(unsigned int id,
                                const struct omap_mcbsp_spi_cfg *spi_cfg)
 {
+       struct omap_mcbsp *mcbsp;
        struct omap_mcbsp_reg_cfg mcbsp_cfg;
 
        if (!omap_mcbsp_check_valid_id(id)) {
                printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
                return;
        }
+       mcbsp = id_to_mcbsp_ptr(id);
 
        memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
 
@@ -803,9 +863,10 @@ EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
  * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
  * 730 has only 2 McBSP, and both of them are MPU peripherals.
  */
-static int __init omap_mcbsp_probe(struct platform_device *pdev)
+static int __devinit omap_mcbsp_probe(struct platform_device *pdev)
 {
        struct omap_mcbsp_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_mcbsp *mcbsp;
        int id = pdev->id - 1;
        int ret = 0;
 
@@ -818,47 +879,63 @@ static int __init omap_mcbsp_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "Initializing OMAP McBSP (%d).\n", pdev->id);
 
-       if (id >= OMAP_MAX_MCBSP_COUNT) {
+       if (id >= omap_mcbsp_count) {
                dev_err(&pdev->dev, "Invalid McBSP device id (%d)\n", id);
                ret = -EINVAL;
                goto exit;
        }
 
-       spin_lock_init(&mcbsp[id].lock);
-       mcbsp[id].id = id + 1;
-       mcbsp[id].free = 1;
-       mcbsp[id].dma_tx_lch = -1;
-       mcbsp[id].dma_rx_lch = -1;
+       mcbsp = kzalloc(sizeof(struct omap_mcbsp), GFP_KERNEL);
+       if (!mcbsp) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+       mcbsp_ptr[id] = mcbsp;
+
+       spin_lock_init(&mcbsp->lock);
+       mcbsp->id = id + 1;
+       mcbsp->free = 1;
+       mcbsp->dma_tx_lch = -1;
+       mcbsp->dma_rx_lch = -1;
+
+       mcbsp->phys_base = pdata->phys_base;
+       mcbsp->io_base = ioremap(pdata->phys_base, SZ_4K);
+       if (!mcbsp->io_base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
-       mcbsp[id].phys_base = pdata->phys_base;
-       mcbsp[id].io_base = pdata->virt_base;
        /* Default I/O is IRQ based */
-       mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO;
-       mcbsp[id].tx_irq = pdata->tx_irq;
-       mcbsp[id].rx_irq = pdata->rx_irq;
-       mcbsp[id].dma_rx_sync = pdata->dma_rx_sync;
-       mcbsp[id].dma_tx_sync = pdata->dma_tx_sync;
+       mcbsp->io_type = OMAP_MCBSP_IRQ_IO;
+       mcbsp->tx_irq = pdata->tx_irq;
+       mcbsp->rx_irq = pdata->rx_irq;
+       mcbsp->dma_rx_sync = pdata->dma_rx_sync;
+       mcbsp->dma_tx_sync = pdata->dma_tx_sync;
 
        if (pdata->clk_name)
-               mcbsp[id].clk = clk_get(&pdev->dev, pdata->clk_name);
-       if (IS_ERR(mcbsp[id].clk)) {
-               mcbsp[id].free = 0;
+               mcbsp->clk = clk_get(&pdev->dev, pdata->clk_name);
+       if (IS_ERR(mcbsp->clk)) {
                dev_err(&pdev->dev,
                        "Invalid clock configuration for McBSP%d.\n",
-                       mcbsp[id].id);
-               ret = -EINVAL;
-               goto exit;
+                       mcbsp->id);
+               ret = PTR_ERR(mcbsp->clk);
+               goto err_clk;
        }
 
-       mcbsp[id].pdata = pdata;
-       mcbsp[id].dev = &pdev->dev;
-       platform_set_drvdata(pdev, &mcbsp[id]);
+       mcbsp->pdata = pdata;
+       mcbsp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mcbsp);
+       return 0;
 
+err_clk:
+       iounmap(mcbsp->io_base);
+err_ioremap:
+       mcbsp->free = 0;
 exit:
        return ret;
 }
 
-static int omap_mcbsp_remove(struct platform_device *pdev)
+static int __devexit omap_mcbsp_remove(struct platform_device *pdev)
 {
        struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
 
@@ -872,6 +949,8 @@ static int omap_mcbsp_remove(struct platform_device *pdev)
                clk_disable(mcbsp->clk);
                clk_put(mcbsp->clk);
 
+               iounmap(mcbsp->io_base);
+
                mcbsp->clk = NULL;
                mcbsp->free = 0;
                mcbsp->dev = NULL;
@@ -882,7 +961,7 @@ static int omap_mcbsp_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_mcbsp_driver = {
        .probe          = omap_mcbsp_probe,
-       .remove         = omap_mcbsp_remove,
+       .remove         = __devexit_p(omap_mcbsp_remove),
        .driver         = {
                .name   = "omap-mcbsp",
        },
diff --git a/arch/arm/plat-omap/mmu.c b/arch/arm/plat-omap/mmu.c
new file mode 100644 (file)
index 0000000..d81a148
--- /dev/null
@@ -0,0 +1,1563 @@
+/*
+ * linux/arch/arm/plat-omap/mmu.c
+ *
+ * OMAP MMU management framework
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation
+ *
+ * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *        and Paul Mundt <lethal@linux-sh.org>
+ *
+ * TWL support: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/mempool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <mach/mmu.h>
+#include <asm/sizes.h>
+#include <mach/dsp_common.h>
+
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../mach-omap2/mmu.h"
+#endif
+
+/*
+ * On OMAP2 MMU_LOCK_xxx_MASK only applies to the IVA and DSP, the camera
+ * MMU has base and victim implemented in different bits in the LOCK
+ * register (shifts are still the same), all of the other registers are
+ * the same on all of the MMUs..
+ */
+#define MMU_LOCK_BASE_SHIFT            10
+#define MMU_LOCK_VICTIM_SHIFT          4
+
+#define CAMERA_MMU_LOCK_BASE_MASK      (0x7 << MMU_LOCK_BASE_SHIFT)
+#define CAMERA_MMU_LOCK_VICTIM_MASK    (0x7 << MMU_LOCK_VICTIM_SHIFT)
+
+#define is_aligned(adr, align) (!((adr)&((align)-1)))
+#define ORDER_1MB      (20 - PAGE_SHIFT)
+#define ORDER_64KB     (16 - PAGE_SHIFT)
+#define ORDER_4KB      (12 - PAGE_SHIFT)
+
+#define MMU_CNTL_EMUTLBUPDATE  (1<<3)
+#define MMU_CNTL_TWLENABLE     (1<<2)
+#define MMU_CNTL_MMUENABLE     (1<<1)
+
+static mempool_t *mempool_1M;
+static mempool_t *mempool_64K;
+
+#define omap_mmu_for_each_tlb_entry(mmu, entry)                        \
+       for (entry = mmu->exmap_tbl; prefetch(entry + 1),       \
+            entry < (mmu->exmap_tbl + mmu->nr_tlb_entries);    \
+            entry++)
+
+#define to_dev(obj)    container_of(obj, struct device, kobj)
+
+static void *mempool_alloc_from_pool(mempool_t *pool,
+                                    unsigned int __nocast gfp_mask)
+{
+       spin_lock_irq(&pool->lock);
+       if (likely(pool->curr_nr)) {
+               void *element = pool->elements[--pool->curr_nr];
+               spin_unlock_irq(&pool->lock);
+               return element;
+       }
+
+       spin_unlock_irq(&pool->lock);
+       return mempool_alloc(pool, gfp_mask);
+}
+
+/*
+ * kmem_reserve(), kmem_release():
+ * reserve or release kernel memory for exmap().
+ *
+ * exmap() might request consecutive 1MB or 64kB,
+ * but it will be difficult after memory pages are fragmented.
+ * So, user can reserve such memory blocks in the early phase
+ * through kmem_reserve().
+ */
+static void *omap_mmu_pool_alloc(unsigned int __nocast gfp, void *order)
+{
+       return (void *)__get_dma_pages(gfp, (unsigned int)order);
+}
+
+static void omap_mmu_pool_free(void *buf, void *order)
+{
+       free_pages((unsigned long)buf, (unsigned int)order);
+}
+
+int omap_mmu_kmem_reserve(struct omap_mmu *mmu, unsigned long size)
+{
+       unsigned long len = size;
+
+       /* alignment check */
+       if (!is_aligned(size, SZ_64K)) {
+               dev_err(mmu->dev,
+                       "MMU %s: size(0x%lx) is not multiple of 64KB.\n",
+                       mmu->name, size);
+               return -EINVAL;
+       }
+
+       if (size > (1 << mmu->addrspace)) {
+               dev_err(mmu->dev,
+                       "MMU %s: size(0x%lx) is larger than external device "
+                       " memory space size (0x%x.\n", mmu->name, size,
+                       (1 << mmu->addrspace));
+               return -EINVAL;
+       }
+
+       if (size >= SZ_1M) {
+               int nr = size >> 20;
+
+               if (likely(!mempool_1M))
+                       mempool_1M = mempool_create(nr, omap_mmu_pool_alloc,
+                                                   omap_mmu_pool_free,
+                                                   (void *)ORDER_1MB);
+               else
+                       mempool_resize(mempool_1M, mempool_1M->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 20);
+       }
+
+       if (size >= SZ_64K) {
+               int nr = size >> 16;
+
+               if (likely(!mempool_64K))
+                       mempool_64K = mempool_create(nr, omap_mmu_pool_alloc,
+                                                    omap_mmu_pool_free,
+                                                    (void *)ORDER_64KB);
+               else
+                       mempool_resize(mempool_64K, mempool_64K->min_nr + nr,
+                                      GFP_KERNEL);
+
+               size &= ~(0xf << 16);
+       }
+
+       if (size)
+               len -= size;
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_reserve);
+
+void omap_mmu_kmem_release(void)
+{
+       if (mempool_64K) {
+               mempool_destroy(mempool_64K);
+               mempool_64K = NULL;
+       }
+
+       if (mempool_1M) {
+               mempool_destroy(mempool_1M);
+               mempool_1M = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(omap_mmu_kmem_release);
+
+static void omap_mmu_free_pages(unsigned long buf, unsigned int order)
+{
+       struct page *page, *ps, *pe;
+
+       ps = virt_to_page(buf);
+       pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
+
+       for (page = ps; page < pe; page++)
+               ClearPageReserved(page);
+
+       if ((order == ORDER_64KB) && likely(mempool_64K))
+               mempool_free((void *)buf, mempool_64K);
+       else if ((order == ORDER_1MB) && likely(mempool_1M))
+               mempool_free((void *)buf, mempool_1M);
+       else
+               free_pages(buf, order);
+}
+
+/*
+ * ARM MMU operations
+ */
+int exmap_set_armmmu(struct omap_mmu *mmu, unsigned long virt,
+                    unsigned long phys, unsigned long size)
+{
+       long off;
+       unsigned long sz_left;
+       pmd_t *pmdp;
+       pte_t *ptep;
+       int prot_pmd, prot_pte;
+
+       dev_dbg(mmu->dev,
+               "MMU %s: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n",
+               mmu->name, virt, phys, size);
+
+       prot_pmd = PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_IO);
+       prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE;
+
+       pmdp = pmd_offset(pgd_offset_k(virt), virt);
+       if (pmd_none(*pmdp)) {
+               ptep = pte_alloc_one_kernel(&init_mm, 0);
+               if (ptep == NULL)
+                       return -ENOMEM;
+               /* note: two PMDs will be set  */
+               pmd_populate_kernel(&init_mm, pmdp, ptep);
+       }
+
+       off = phys - virt;
+       for (sz_left = size;
+            sz_left >= PAGE_SIZE;
+            sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+               ptep = pte_offset_kernel(pmdp, virt);
+               set_pte_ext(ptep, __pte((virt + off) | prot_pte), 0);
+       }
+       if (sz_left)
+               BUG();
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(exmap_set_armmmu);
+
+void exmap_clear_armmmu(struct omap_mmu *mmu, unsigned long virt,
+                       unsigned long size)
+{
+       unsigned long sz_left;
+       pmd_t *pmdp;
+       pte_t *ptep;
+
+       dev_dbg(mmu->dev,
+               "MMU %s: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n",
+               mmu->name, virt, size);
+
+       for (sz_left = size;
+            sz_left >= PAGE_SIZE;
+            sz_left -= PAGE_SIZE, virt += PAGE_SIZE) {
+               pmdp = pmd_offset(pgd_offset_k(virt), virt);
+               ptep = pte_offset_kernel(pmdp, virt);
+               pte_clear(&init_mm, virt, ptep);
+       }
+       if (sz_left)
+               BUG();
+}
+EXPORT_SYMBOL_GPL(exmap_clear_armmmu);
+
+int exmap_valid(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       /* exmap_sem should be held before calling this function */
+       struct exmap_tbl *ent;
+
+start:
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       if (vadr + len <= mapadr + mapsize) {
+                               /* this map covers whole address. */
+                               return 1;
+                       } else {
+                               /*
+                                * this map covers partially.
+                                * check rest portion.
+                                */
+                               len -= mapadr + mapsize - vadr;
+                               vadr = mapadr + mapsize;
+                               goto start;
+                       }
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(exmap_valid);
+
+/*
+ * omap_mmu_exmap_use(), unuse():
+ * when the mapped area is exported to user space with mmap,
+ * the usecount is incremented.
+ * while the usecount > 0, that area can't be released.
+ */
+void omap_mmu_exmap_use(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount++;
+       }
+       up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_use);
+
+void omap_mmu_exmap_unuse(struct omap_mmu *mmu, void *vadr, size_t len)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr + len > mapadr) && (vadr < mapadr + mapsize))
+                       ent->usecount--;
+       }
+       up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_unuse);
+
+/*
+ * omap_mmu_virt_to_phys()
+ * returns physical address, and sets len to valid length
+ */
+unsigned long
+omap_mmu_virt_to_phys(struct omap_mmu *mmu, void *vadr, size_t *len)
+{
+       struct exmap_tbl *ent;
+
+       if (omap_mmu_internal_memory(mmu, vadr)) {
+               unsigned long addr = (unsigned long)vadr;
+               *len = mmu->membase + mmu->memsize - addr;
+               return addr;
+       }
+
+       /* EXRAM */
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *mapadr;
+               unsigned long mapsize;
+
+               if (!ent->valid)
+                       continue;
+               mapadr = (void *)ent->vadr;
+               mapsize = 1 << (ent->order + PAGE_SHIFT);
+               if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) {
+                       *len = mapadr + mapsize - vadr;
+                       return __pa(ent->buf) + vadr - mapadr;
+               }
+       }
+
+       /* valid mapping not found */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_virt_to_phys);
+
+/*
+ * PTE operations
+ */
+static inline void
+omap_mmu_alloc_section(struct mm_struct *mm, unsigned long virt,
+                      unsigned long phys, int prot)
+{
+       pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+       if (virt & (1 << SECTION_SHIFT))
+               pmdp++;
+       *pmdp = __pmd((phys & SECTION_MASK) | prot | PMD_TYPE_SECT);
+       flush_pmd_entry(pmdp);
+}
+
+static inline void
+omap_mmu_alloc_supersection(struct mm_struct *mm, unsigned long virt,
+                           unsigned long phys, int prot)
+{
+       int i;
+       for (i = 0; i < 16; i += 1) {
+               omap_mmu_alloc_section(mm, virt, phys, prot | PMD_SECT_SUPER);
+               virt += (PGDIR_SIZE / 2);
+       }
+}
+
+static inline int
+omap_mmu_alloc_page(struct mm_struct *mm, unsigned long virt,
+                   unsigned long phys, pgprot_t prot)
+{
+       pte_t *ptep;
+       pmd_t *pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+       if (!(prot & PTE_TYPE_MASK))
+               prot |= PTE_TYPE_SMALL;
+
+       if (pmd_none(*pmdp)) {
+               ptep = pte_alloc_one_kernel(mm, virt);
+               if (ptep == NULL)
+                       return -ENOMEM;
+               pmd_populate_kernel(mm, pmdp, ptep);
+       }
+       ptep = pte_offset_kernel(pmdp, virt);
+       ptep -= PTRS_PER_PTE;
+       *ptep = pfn_pte(phys >> PAGE_SHIFT, prot);
+       flush_pmd_entry((pmd_t *)ptep);
+       return 0;
+}
+
+static inline int
+omap_mmu_alloc_largepage(struct mm_struct *mm, unsigned long virt,
+                        unsigned long phys, pgprot_t prot)
+{
+       int i, ret;
+       for (i = 0; i < 16; i += 1) {
+               ret = omap_mmu_alloc_page(mm, virt, phys,
+                                         prot | PTE_TYPE_LARGE);
+               if (ret)
+                       return -ENOMEM; /* only 1st time */
+               virt += PAGE_SIZE;
+       }
+       return 0;
+}
+
+static int omap_mmu_load_pte(struct omap_mmu *mmu,
+                            struct omap_mmu_tlb_entry *e)
+{
+       int ret = 0;
+       struct mm_struct *mm = mmu->twl_mm;
+       const unsigned long va = e->va;
+       const unsigned long pa = e->pa;
+       const pgprot_t prot = mmu->ops->pte_get_attr(e);
+
+       spin_lock(&mm->page_table_lock);
+
+       switch (e->pgsz) {
+       case OMAP_MMU_CAM_PAGESIZE_16MB:
+               omap_mmu_alloc_supersection(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_1MB:
+               omap_mmu_alloc_section(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_64KB:
+               ret = omap_mmu_alloc_largepage(mm, va, pa, prot);
+               break;
+       case OMAP_MMU_CAM_PAGESIZE_4KB:
+               ret = omap_mmu_alloc_page(mm, va, pa, prot);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       spin_unlock(&mm->page_table_lock);
+
+       return ret;
+}
+
+static void omap_mmu_clear_pte(struct omap_mmu *mmu, unsigned long virt)
+{
+       pte_t *ptep, *end;
+       pmd_t *pmdp;
+       struct mm_struct *mm = mmu->twl_mm;
+
+       spin_lock(&mm->page_table_lock);
+
+       pmdp = pmd_offset(pgd_offset(mm, virt), virt);
+
+       if (pmd_none(*pmdp))
+               goto out;
+
+       if (!pmd_table(*pmdp))
+               goto invalidate_pmd;
+
+       ptep = pte_offset_kernel(pmdp, virt);
+       pte_clear(mm, virt, ptep);
+       flush_pmd_entry((pmd_t *)ptep);
+
+       /* zap pte */
+       end = pmd_page_vaddr(*pmdp);
+       ptep = end - PTRS_PER_PTE;
+       while (ptep < end) {
+               if (!pte_none(*ptep))
+                       goto out;
+               ptep++;
+       }
+       pte_free_kernel(mm, pmd_page_vaddr(*pmdp));
+
+ invalidate_pmd:
+       pmd_clear(pmdp);
+       flush_pmd_entry(pmdp);
+ out:
+       spin_unlock(&mm->page_table_lock);
+}
+
+/*
+ * TLB operations
+ */
+static struct cam_ram_regset *
+omap_mmu_cam_ram_alloc(struct omap_mmu *mmu, struct omap_mmu_tlb_entry *entry)
+{
+       return mmu->ops->cam_ram_alloc(mmu, entry);
+}
+
+static int omap_mmu_cam_ram_valid(struct omap_mmu *mmu,
+                                 struct cam_ram_regset *cr)
+{
+       return mmu->ops->cam_ram_valid(cr);
+}
+
+static inline void
+omap_mmu_get_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *tlb_lock)
+{
+       unsigned long lock = omap_mmu_read_reg(mmu, OMAP_MMU_LOCK);
+       int mask;
+
+       mask = (mmu->type == OMAP_MMU_CAMERA) ?
+                       CAMERA_MMU_LOCK_BASE_MASK : MMU_LOCK_BASE_MASK;
+       tlb_lock->base = (lock & mask) >> MMU_LOCK_BASE_SHIFT;
+
+       mask = (mmu->type == OMAP_MMU_CAMERA) ?
+                       CAMERA_MMU_LOCK_VICTIM_MASK : MMU_LOCK_VICTIM_MASK;
+       tlb_lock->victim = (lock & mask) >> MMU_LOCK_VICTIM_SHIFT;
+}
+
+static inline void
+omap_mmu_set_tlb_lock(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock)
+{
+       omap_mmu_write_reg(mmu,
+                          (lock->base << MMU_LOCK_BASE_SHIFT) |
+                          (lock->victim << MMU_LOCK_VICTIM_SHIFT),
+                          OMAP_MMU_LOCK);
+}
+
+static inline void omap_mmu_flush(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_FLUSH_ENTRY);
+}
+
+static inline void omap_mmu_ldtlb(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_LD_TLB);
+}
+
+void omap_mmu_read_tlb(struct omap_mmu *mmu, struct omap_mmu_tlb_lock *lock,
+                      struct cam_ram_regset *cr)
+{
+       /* set victim */
+       omap_mmu_set_tlb_lock(mmu, lock);
+
+       if (likely(mmu->ops->read_tlb))
+               mmu->ops->read_tlb(mmu, cr);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_read_tlb);
+
+void omap_mmu_load_tlb(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       if (likely(mmu->ops->load_tlb))
+               mmu->ops->load_tlb(mmu, cr);
+
+       /* flush the entry */
+       omap_mmu_flush(mmu);
+
+       /* load a TLB entry */
+       omap_mmu_ldtlb(mmu);
+}
+
+int omap_mmu_load_tlb_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry)
+{
+       struct omap_mmu_tlb_lock lock;
+       struct cam_ram_regset *cr;
+       int ret;
+
+       clk_enable(mmu->clk);
+       ret = omap_dsp_request_mem();
+       if (ret < 0)
+               goto out;
+
+       omap_mmu_get_tlb_lock(mmu, &lock);
+       for (lock.victim = 0; lock.victim < lock.base; lock.victim++) {
+               struct cam_ram_regset tmp;
+
+               /* read a TLB entry */
+               omap_mmu_read_tlb(mmu, &lock, &tmp);
+               if (!omap_mmu_cam_ram_valid(mmu, &tmp))
+                       goto found_victim;
+       }
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+found_victim:
+       /* The last entry cannot be locked? */
+       if (lock.victim == (mmu->nr_tlb_entries - 1)) {
+               dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
+               return -EBUSY;
+       }
+
+       cr = omap_mmu_cam_ram_alloc(mmu, entry);
+       if (IS_ERR(cr))
+               return PTR_ERR(cr);
+
+       omap_mmu_load_tlb(mmu, cr);
+       kfree(cr);
+
+       /* update lock base */
+       if (lock.victim == lock.base)
+               lock.base++;
+
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+out:
+       clk_disable(mmu->clk);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_tlb_entry);
+
+static inline unsigned long
+omap_mmu_cam_va(struct omap_mmu *mmu, struct cam_ram_regset *cr)
+{
+       return mmu->ops->cam_va(cr);
+}
+
+int omap_mmu_clear_tlb_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+       struct omap_mmu_tlb_lock lock;
+       int i, ret = 0;
+       int max_valid = 0;
+
+       clk_enable(mmu->clk);
+       ret = omap_dsp_request_mem();
+       if (ret < 0)
+               goto out;
+
+       omap_mmu_get_tlb_lock(mmu, &lock);
+       for (i = 0; i < lock.base; i++) {
+               struct cam_ram_regset cr;
+
+               /* read a TLB entry */
+               lock.victim = i;
+               omap_mmu_read_tlb(mmu, &lock, &cr);
+               if (!omap_mmu_cam_ram_valid(mmu, &cr))
+                       continue;
+
+               if (omap_mmu_cam_va(mmu, &cr) == vadr)
+                       /* flush the entry */
+                       omap_mmu_flush(mmu);
+               else
+                       max_valid = i;
+       }
+
+       /* set new lock base */
+       lock.base = lock.victim = max_valid + 1;
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+out:
+       clk_disable(mmu->clk);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_tlb_entry);
+
+static void omap_mmu_gflush(struct omap_mmu *mmu)
+{
+       struct omap_mmu_tlb_lock lock;
+       int ret;
+
+       clk_enable(mmu->clk);
+       ret = omap_dsp_request_mem();
+       if (ret < 0)
+               goto out;
+
+       omap_mmu_write_reg(mmu, 0x1, OMAP_MMU_GFLUSH);
+       lock.base = lock.victim = mmu->nr_exmap_preserved;
+       omap_mmu_set_tlb_lock(mmu, &lock);
+
+       omap_dsp_release_mem();
+out:
+       clk_disable(mmu->clk);
+}
+
+int omap_mmu_load_pte_entry(struct omap_mmu *mmu,
+                           struct omap_mmu_tlb_entry *entry)
+{
+       int ret = -1;
+       /*XXX use PG_flag for prsvd */
+       ret = omap_mmu_load_pte(mmu, entry);
+       if (ret)
+               return ret;
+       if (entry->tlb)
+               ret = omap_mmu_load_tlb_entry(mmu, entry);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_load_pte_entry);
+
+int omap_mmu_clear_pte_entry(struct omap_mmu *mmu, unsigned long vadr)
+{
+       int ret = omap_mmu_clear_tlb_entry(mmu, vadr);
+       if (ret)
+               return ret;
+       omap_mmu_clear_pte(mmu, vadr);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_clear_pte_entry);
+
+/*
+ * omap_mmu_exmap()
+ *
+ * MEM_IOCTL_EXMAP ioctl calls this function with padr=0.
+ * In this case, the buffer for external device is allocated in this routine,
+ * then it is mapped.
+ * On the other hand, for example - frame buffer sharing, calls
+ * this function with padr set. It means some known address space
+ * pointed with padr is going to be shared with external device.
+ */
+int omap_mmu_exmap(struct omap_mmu *mmu, unsigned long devadr,
+                  unsigned long padr, unsigned long size,
+                  enum exmap_type type)
+{
+       unsigned long pgsz;
+       void *buf;
+       unsigned int order = 0;
+       unsigned long unit;
+       int prev = -1;
+       unsigned long _devadr = devadr;
+       unsigned long _padr = padr;
+       void *_vadr = omap_mmu_to_virt(mmu, devadr);
+       unsigned long _size = size;
+       struct omap_mmu_tlb_entry tlb_ent;
+       struct exmap_tbl *exmap_ent, *tmp_ent;
+       int status;
+       int idx;
+
+#define MINIMUM_PAGESZ SZ_4K
+       /*
+        * alignment check
+        */
+       if (!is_aligned(size, MINIMUM_PAGESZ)) {
+               dev_err(mmu->dev,
+                       "MMU %s: size(0x%lx) is not multiple of 4KB.\n",
+                       mmu->name, size);
+               return -EINVAL;
+       }
+       if (!is_aligned(devadr, MINIMUM_PAGESZ)) {
+               dev_err(mmu->dev,
+                       "MMU %s: external device address(0x%lx) is not"
+                       " aligned.\n", mmu->name, devadr);
+               return -EINVAL;
+       }
+       if (!is_aligned(padr, MINIMUM_PAGESZ)) {
+               dev_err(mmu->dev,
+                       "MMU %s: physical address(0x%lx) is not aligned.\n",
+                       mmu->name, padr);
+               return -EINVAL;
+       }
+
+       /* address validity check */
+       if ((devadr < mmu->memsize) ||
+           (devadr >= (1 << mmu->addrspace))) {
+               dev_err(mmu->dev,
+                       "MMU %s: illegal address/size for %s().\n",
+                       mmu->name, __func__);
+               return -EINVAL;
+       }
+
+       down_write(&mmu->exmap_sem);
+
+       /* overlap check */
+       omap_mmu_for_each_tlb_entry(mmu, tmp_ent) {
+               unsigned long mapsize;
+
+               if (!tmp_ent->valid)
+                       continue;
+               mapsize = 1 << (tmp_ent->order + PAGE_SHIFT);
+               if ((_vadr + size > tmp_ent->vadr) &&
+                   (_vadr < tmp_ent->vadr + mapsize)) {
+                       dev_err(mmu->dev, "MMU %s: exmap page overlap!\n",
+                               mmu->name);
+                       up_write(&mmu->exmap_sem);
+                       return -EINVAL;
+               }
+       }
+
+start:
+       buf = NULL;
+       /* Are there any free TLB lines?  */
+       for (idx = 0; idx < mmu->nr_tlb_entries; idx++)
+               if (!mmu->exmap_tbl[idx].valid)
+                       goto found_free;
+
+       dev_err(mmu->dev, "MMU %s: TLB is full.\n", mmu->name);
+       status = -EBUSY;
+       goto fail;
+
+found_free:
+       exmap_ent = mmu->exmap_tbl + idx;
+
+       if ((_size >= SZ_1M) &&
+           (is_aligned(_padr, SZ_1M) || (padr == 0)) &&
+           is_aligned(_devadr, SZ_1M)) {
+               unit = SZ_1M;
+               pgsz = OMAP_MMU_CAM_PAGESIZE_1MB;
+       } else if ((_size >= SZ_64K) &&
+                  (is_aligned(_padr, SZ_64K) || (padr == 0)) &&
+                  is_aligned(_devadr, SZ_64K)) {
+               unit = SZ_64K;
+               pgsz = OMAP_MMU_CAM_PAGESIZE_64KB;
+       } else {
+               unit = SZ_4K;
+               pgsz = OMAP_MMU_CAM_PAGESIZE_4KB;
+       }
+
+       order = get_order(unit);
+
+       /* buffer allocation */
+       if (type == EXMAP_TYPE_MEM) {
+               struct page *page, *ps, *pe;
+
+               if ((order == ORDER_1MB) && likely(mempool_1M))
+                       buf = mempool_alloc_from_pool(mempool_1M, GFP_KERNEL);
+               else if ((order == ORDER_64KB) && likely(mempool_64K))
+                       buf = mempool_alloc_from_pool(mempool_64K, GFP_KERNEL);
+               else {
+                       buf = (void *)__get_dma_pages(GFP_KERNEL, order);
+                       if (buf == NULL) {
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+               }
+
+               /* mark the pages as reserved; this is needed for mmap */
+               ps = virt_to_page(buf);
+               pe = virt_to_page(buf + unit);
+
+               for (page = ps; page < pe; page++)
+                       SetPageReserved(page);
+
+               _padr = __pa(buf);
+       }
+
+       /*
+        * mapping for ARM MMU:
+        * we should not access to the allocated memory through 'buf'
+        * since this area should not be cached.
+        */
+       status = exmap_set_armmmu(mmu, (unsigned long)_vadr, _padr, unit);
+       if (status < 0)
+               goto fail;
+
+       /* loading external device PTE entry */
+       INIT_TLB_ENTRY(&tlb_ent, _devadr, _padr, pgsz);
+       status = omap_mmu_load_pte_entry(mmu, &tlb_ent);
+       if (status < 0) {
+               exmap_clear_armmmu(mmu, (unsigned long)_vadr, unit);
+               goto fail;
+       }
+
+       INIT_EXMAP_TBL_ENTRY(exmap_ent, buf, _vadr, type, order);
+       exmap_ent->link.prev = prev;
+       if (prev >= 0)
+               mmu->exmap_tbl[prev].link.next = idx;
+
+       if ((_size -= unit) == 0) {     /* normal completion */
+               up_write(&mmu->exmap_sem);
+               return size;
+       }
+
+       _devadr += unit;
+       _vadr   += unit;
+       _padr = padr ? _padr + unit : 0;
+       prev = idx;
+       goto start;
+
+fail:
+       up_write(&mmu->exmap_sem);
+       if (buf)
+               omap_mmu_free_pages((unsigned long)buf, order);
+       omap_mmu_exunmap(mmu, devadr);
+       return status;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap);
+
+static unsigned long unmap_free_arm(struct omap_mmu *mmu,
+                                   struct exmap_tbl *ent)
+{
+       unsigned long size;
+
+       /* clearing ARM MMU */
+       size = 1 << (ent->order + PAGE_SHIFT);
+       exmap_clear_armmmu(mmu, (unsigned long)ent->vadr, size);
+
+       /* freeing allocated memory */
+       if (ent->type == EXMAP_TYPE_MEM) {
+               omap_mmu_free_pages((unsigned long)ent->buf, ent->order);
+               dev_dbg(mmu->dev, "MMU %s: freeing 0x%lx bytes @ adr 0x%8p\n",
+                       mmu->name, size, ent->buf);
+       }
+
+       ent->valid = 0;
+       return size;
+}
+
+int omap_mmu_exunmap(struct omap_mmu *mmu, unsigned long devadr)
+{
+       void *vadr;
+       unsigned long size;
+       int total = 0;
+       struct exmap_tbl *ent;
+       int idx;
+
+       vadr = omap_mmu_to_virt(mmu, devadr);
+       down_write(&mmu->exmap_sem);
+       for (idx = 0; idx < mmu->nr_tlb_entries; idx++) {
+               ent = mmu->exmap_tbl + idx;
+               if (!ent->valid || ent->prsvd)
+                       continue;
+               if (ent->vadr == vadr)
+                       goto found_map;
+       }
+       up_write(&mmu->exmap_sem);
+       dev_warn(mmu->dev, "MMU %s: address %06lx not found in exmap_tbl.\n",
+                mmu->name, devadr);
+       return -EINVAL;
+
+found_map:
+       if (ent->usecount > 0) {
+               dev_err(mmu->dev, "MMU %s: exmap reference count is not 0.\n"
+                       "   idx=%d, vadr=%p, order=%d, usecount=%d\n",
+                       mmu->name, idx, ent->vadr, ent->order, ent->usecount);
+               up_write(&mmu->exmap_sem);
+               return -EINVAL;
+       }
+       /* clearing external device PTE entry */
+       omap_mmu_clear_pte_entry(mmu, devadr);
+
+       /* clear ARM MMU and free buffer */
+       size = unmap_free_arm(mmu, ent);
+       total += size;
+
+       /* we don't free PTEs */
+
+       /* flush TLB */
+       flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size);
+
+       /* check if next mapping is in same group */
+       idx = ent->link.next;
+       if (idx < 0)
+               goto up_out;    /* normal completion */
+       ent = mmu->exmap_tbl + idx;
+       devadr += size;
+       vadr   += size;
+       if (ent->vadr == vadr)
+               goto found_map; /* continue */
+
+       dev_err(mmu->dev, "MMU %s: illegal exmap_tbl grouping!\n"
+               "expected vadr = %p, exmap_tbl[%d].vadr = %p\n",
+               mmu->name, vadr, idx, ent->vadr);
+       up_write(&mmu->exmap_sem);
+       return -EINVAL;
+
+up_out:
+       up_write(&mmu->exmap_sem);
+       return total;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exunmap);
+
+void omap_mmu_exmap_flush(struct omap_mmu *mmu)
+{
+       struct exmap_tbl *ent;
+
+       down_write(&mmu->exmap_sem);
+
+       /* clearing TLB entry */
+       omap_mmu_gflush(mmu);
+
+       omap_mmu_for_each_tlb_entry(mmu, ent)
+               if (ent->valid && !ent->prsvd)
+                       unmap_free_arm(mmu, ent);
+
+       /* flush TLB */
+       if (likely(mmu->membase))
+               flush_tlb_kernel_range(mmu->membase + mmu->memsize,
+                                      mmu->membase + (1 << mmu->addrspace));
+
+       up_write(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_exmap_flush);
+
+void exmap_setup_preserved_mem_page(struct omap_mmu *mmu, void *buf,
+                                   unsigned long devadr, int index)
+{
+       unsigned long phys;
+       void *virt;
+       struct omap_mmu_tlb_entry tlb_ent;
+
+       phys = __pa(buf);
+       virt = omap_mmu_to_virt(mmu, devadr);
+       exmap_set_armmmu(mmu, (unsigned long)virt, phys, PAGE_SIZE);
+       INIT_EXMAP_TBL_ENTRY_4KB_PRESERVED(mmu->exmap_tbl + index, buf, virt);
+       INIT_TLB_ENTRY_4KB_PRESERVED(&tlb_ent, devadr, phys);
+       omap_mmu_load_pte_entry(mmu, &tlb_ent);
+}
+EXPORT_SYMBOL_GPL(exmap_setup_preserved_mem_page);
+
+void exmap_clear_mem_page(struct omap_mmu *mmu, unsigned long devadr)
+{
+       void *virt = omap_mmu_to_virt(mmu, devadr);
+
+       exmap_clear_armmmu(mmu, (unsigned long)virt, PAGE_SIZE);
+       /* DSP MMU is shutting down. not handled here. */
+}
+EXPORT_SYMBOL_GPL(exmap_clear_mem_page);
+
+static void omap_mmu_reset(struct omap_mmu *mmu)
+{
+#if defined(CONFIG_ARCH_OMAP2) /* FIXME */
+       int i;
+
+       omap_mmu_write_reg(mmu, 0x2, OMAP_MMU_SYSCONFIG);
+
+       for (i = 0; i < 10000; i++)
+               if (likely(omap_mmu_read_reg(mmu, OMAP_MMU_SYSSTATUS) & 0x1))
+                       break;
+#endif
+}
+
+void omap_mmu_disable(struct omap_mmu *mmu)
+{
+       omap_mmu_write_reg(mmu, 0x00, OMAP_MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_disable);
+
+void omap_mmu_enable(struct omap_mmu *mmu, int reset)
+{
+       u32 val = OMAP_MMU_CNTL_MMU_EN | MMU_CNTL_TWLENABLE;
+
+       if (likely(reset))
+               omap_mmu_reset(mmu);
+#if defined(CONFIG_ARCH_OMAP2) /* FIXME */
+       omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd),
+                          OMAP_MMU_TTB);
+#else
+       omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd) & 0xffff,
+                          OMAP_MMU_TTB_L);
+       omap_mmu_write_reg(mmu, (u32)virt_to_phys(mmu->twl_mm->pgd) >> 16,
+                          OMAP_MMU_TTB_H);
+       val |= OMAP_MMU_CNTL_RESET_SW;
+#endif
+       omap_mmu_write_reg(mmu, val, OMAP_MMU_CNTL);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_enable);
+
+static irqreturn_t omap_mmu_interrupt(int irq, void *dev_id)
+{
+       struct omap_mmu *mmu = dev_id;
+
+       if (likely(mmu->ops->interrupt))
+               mmu->ops->interrupt(mmu);
+
+       return IRQ_HANDLED;
+}
+
+static int omap_mmu_init(struct omap_mmu *mmu)
+{
+       struct omap_mmu_tlb_lock tlb_lock;
+       int ret = 0;
+
+       clk_enable(mmu->clk);
+       ret = omap_dsp_request_mem();
+       if (ret < 0)
+               goto out;
+
+       down_write(&mmu->exmap_sem);
+
+       ret = request_irq(mmu->irq, omap_mmu_interrupt, IRQF_DISABLED,
+                         mmu->name,  mmu);
+       if (ret < 0) {
+               dev_err(mmu->dev, "MMU %s: failed to register MMU interrupt:"
+                       " %d\n", mmu->name, ret);
+               goto fail;
+       }
+
+       omap_mmu_disable(mmu);  /* clear all */
+       udelay(100);
+       omap_mmu_enable(mmu, 1);
+
+       memset(&tlb_lock, 0, sizeof(struct omap_mmu_tlb_lock));
+       omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+       if (unlikely(mmu->ops->startup))
+               ret = mmu->ops->startup(mmu);
+fail:
+       up_write(&mmu->exmap_sem);
+       omap_dsp_release_mem();
+out:
+       clk_disable(mmu->clk);
+
+       return ret;
+}
+
+static void omap_mmu_shutdown(struct omap_mmu *mmu)
+{
+       free_irq(mmu->irq, mmu);
+
+       if (unlikely(mmu->ops->shutdown))
+               mmu->ops->shutdown(mmu);
+
+       omap_mmu_exmap_flush(mmu);
+       omap_mmu_disable(mmu); /* clear all */
+}
+
+/*
+ * omap_mmu_mem_enable() / disable()
+ */
+int omap_mmu_mem_enable(struct omap_mmu *mmu, void *addr)
+{
+       if (unlikely(mmu->ops->mem_enable))
+               return mmu->ops->mem_enable(mmu, addr);
+
+       down_read(&mmu->exmap_sem);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_enable);
+
+void omap_mmu_mem_disable(struct omap_mmu *mmu, void *addr)
+{
+       if (unlikely(mmu->ops->mem_disable)) {
+               mmu->ops->mem_disable(mmu, addr);
+               return;
+       }
+
+       up_read(&mmu->exmap_sem);
+}
+EXPORT_SYMBOL_GPL(omap_mmu_mem_disable);
+
+/*
+ * dsp_mem file operations
+ */
+static ssize_t intmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       ssize_t size = mmu->memsize;
+       ssize_t read;
+
+       if (p >= size)
+               return 0;
+       clk_enable(mmu->memclk);
+       read = count;
+       if (count > size - p)
+               read = size - p;
+       if (copy_to_user(buf, vadr, read)) {
+               read = -EFAULT;
+               goto out;
+       }
+       *ppos += read;
+out:
+       clk_disable(mmu->memclk);
+       return read;
+}
+
+static ssize_t exmem_read(struct omap_mmu *mmu, char *buf, size_t count,
+                         loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+
+       if (!exmap_valid(mmu, vadr, count)) {
+               dev_err(mmu->dev, "MMU %s: external device address %08lx / "
+                       "size %08x is not valid!\n", mmu->name, p, count);
+               return -EFAULT;
+       }
+       if (count > (1 << mmu->addrspace) - p)
+               count = (1 << mmu->addrspace) - p;
+       if (copy_to_user(buf, vadr, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t omap_mmu_mem_read(struct kobject *kobj,
+                                struct bin_attribute *attr,
+                                char *buf, loff_t offset, size_t count)
+{
+       struct device *dev = to_dev(kobj);
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long p = (unsigned long)offset;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       int ret;
+
+       if (omap_mmu_mem_enable(mmu, vadr) < 0)
+               return -EBUSY;
+
+       if (p < mmu->memsize)
+               ret = intmem_read(mmu, buf, count, &offset);
+       else
+               ret = exmem_read(mmu, buf, count, &offset);
+
+       omap_mmu_mem_disable(mmu, vadr);
+
+       return ret;
+}
+
+static ssize_t intmem_write(struct omap_mmu *mmu, const char *buf, size_t count,
+                           loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       ssize_t size = mmu->memsize;
+       ssize_t written;
+
+       if (p >= size)
+               return 0;
+       clk_enable(mmu->memclk);
+       written = count;
+       if (count > size - p)
+               written = size - p;
+       if (copy_from_user(vadr, buf, written)) {
+               written = -EFAULT;
+               goto out;
+       }
+       *ppos += written;
+out:
+       clk_disable(mmu->memclk);
+       return written;
+}
+
+static ssize_t exmem_write(struct omap_mmu *mmu, char *buf, size_t count,
+                          loff_t *ppos)
+{
+       unsigned long p = *ppos;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+
+       if (!exmap_valid(mmu, vadr, count)) {
+               dev_err(mmu->dev, "MMU %s: external device address %08lx "
+                       "/ size %08x is not valid!\n", mmu->name, p, count);
+               return -EFAULT;
+       }
+       if (count > (1 << mmu->addrspace) - p)
+               count = (1 << mmu->addrspace) - p;
+       if (copy_from_user(vadr, buf, count))
+               return -EFAULT;
+       *ppos += count;
+
+       return count;
+}
+
+static ssize_t omap_mmu_mem_write(struct kobject *kobj,
+                                 struct bin_attribute *attr,
+                                 char *buf, loff_t offset, size_t count)
+{
+       struct device *dev = to_dev(kobj);
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long p = (unsigned long)offset;
+       void *vadr = omap_mmu_to_virt(mmu, p);
+       int ret;
+
+       if (omap_mmu_mem_enable(mmu, vadr) < 0)
+               return -EBUSY;
+
+       if (p < mmu->memsize)
+               ret = intmem_write(mmu, buf, count, &offset);
+       else
+               ret = exmem_write(mmu, buf, count, &offset);
+
+       omap_mmu_mem_disable(mmu, vadr);
+
+       return ret;
+}
+
+static struct bin_attribute dev_attr_mem = {
+       .attr   = {
+               .name   = "mem",
+               .owner  = THIS_MODULE,
+               .mode   = S_IRUSR | S_IWUSR | S_IRGRP,
+       },
+
+       .read   = omap_mmu_mem_read,
+       .write  = omap_mmu_mem_write,
+};
+
+/* To be obsolete for backward compatibility */
+ssize_t __omap_mmu_mem_read(struct omap_mmu *mmu,
+                           struct bin_attribute *attr,
+                           char *buf, loff_t offset, size_t count)
+{
+       return omap_mmu_mem_read(&mmu->dev->kobj, attr, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_read);
+
+ssize_t __omap_mmu_mem_write(struct omap_mmu *mmu,
+                            struct bin_attribute *attr,
+                            char *buf, loff_t offset, size_t count)
+{
+       return omap_mmu_mem_write(&mmu->dev->kobj, attr, buf, offset, count);
+}
+EXPORT_SYMBOL_GPL(__omap_mmu_mem_write);
+
+/*
+ * sysfs files
+ */
+static ssize_t omap_mmu_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       struct omap_mmu_tlb_lock tlb_lock;
+       int ret;
+
+       clk_enable(mmu->clk);
+       ret = omap_dsp_request_mem();
+       if (ret < 0)
+               goto out;
+
+       down_read(&mmu->exmap_sem);
+
+       omap_mmu_get_tlb_lock(mmu, &tlb_lock);
+
+       ret = -EIO;
+       if (likely(mmu->ops->show))
+               ret = mmu->ops->show(mmu, buf, &tlb_lock);
+
+       /* restore victim entry */
+       omap_mmu_set_tlb_lock(mmu, &tlb_lock);
+
+       up_read(&mmu->exmap_sem);
+       omap_dsp_release_mem();
+out:
+       clk_disable(mmu->clk);
+
+       return ret;
+}
+
+static DEVICE_ATTR(mmu, S_IRUGO, omap_mmu_show, NULL);
+
+static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       struct exmap_tbl *ent;
+       int len;
+       int i = 0;
+
+       down_read(&mmu->exmap_sem);
+       len = sprintf(buf, "  devadr     size         buf     size uc\n");
+                        /* 0x300000 0x123000  0xc0171000 0x100000  0*/
+
+       omap_mmu_for_each_tlb_entry(mmu, ent) {
+               void *vadr;
+               unsigned long size;
+               enum exmap_type type;
+               int idx;
+
+               /* find a top of link */
+               if (!ent->valid || (ent->link.prev >= 0))
+                       continue;
+
+               vadr = ent->vadr;
+               type = ent->type;
+               size = 0;
+               idx = i;
+               do {
+                       ent = mmu->exmap_tbl + idx;
+                       size += PAGE_SIZE << ent->order;
+               } while ((idx = ent->link.next) >= 0);
+
+               len += sprintf(buf + len, "0x%06lx %#8lx",
+                              virt_to_omap_mmu(mmu, vadr), size);
+
+               if (type == EXMAP_TYPE_FB) {
+                       len += sprintf(buf + len, "    framebuf\n");
+               } else {
+                       len += sprintf(buf + len, "\n");
+                       idx = i;
+                       do {
+                               ent = mmu->exmap_tbl + idx;
+                               len += sprintf(buf + len,
+                                              /* 0xc0171000 0x100000  0*/
+                                              "%19s0x%8p %#8lx %2d\n",
+                                              "", ent->buf,
+                                              PAGE_SIZE << ent->order,
+                                              ent->usecount);
+                       } while ((idx = ent->link.next) >= 0);
+               }
+
+               i++;
+       }
+
+       up_read(&mmu->exmap_sem);
+       return len;
+}
+
+static ssize_t exmap_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf,
+                          size_t count)
+{
+       struct omap_mmu *mmu = dev_get_drvdata(dev);
+       unsigned long base = 0, len = 0;
+       int ret;
+
+       sscanf(buf, "%lx %lx", &base, &len);
+
+       if (!base)
+               return -EINVAL;
+
+       if (len) {
+               /* Add the mapping */
+               ret = omap_mmu_exmap(mmu, base, 0, len, EXMAP_TYPE_MEM);
+               if (ret < 0)
+                       return ret;
+       } else {
+               /* Remove the mapping */
+               ret = omap_mmu_exunmap(mmu, base);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(exmap, S_IRUGO | S_IWUSR, exmap_show, exmap_store);
+
+static ssize_t mempool_show(struct class *class, char *buf)
+{
+       int min_nr_1M = 0, curr_nr_1M = 0;
+       int min_nr_64K = 0, curr_nr_64K = 0;
+       int total = 0;
+
+       if (likely(mempool_1M)) {
+               min_nr_1M  = mempool_1M->min_nr;
+               curr_nr_1M = mempool_1M->curr_nr;
+               total += min_nr_1M * SZ_1M;
+       }
+       if (likely(mempool_64K)) {
+               min_nr_64K  = mempool_64K->min_nr;
+               curr_nr_64K = mempool_64K->curr_nr;
+               total += min_nr_64K * SZ_64K;
+       }
+
+       return sprintf(buf,
+                      "0x%x\n"
+                      "1M  buffer: %d (%d free)\n"
+                      "64K buffer: %d (%d free)\n",
+                      total, min_nr_1M, curr_nr_1M, min_nr_64K, curr_nr_64K);
+}
+
+
+static CLASS_ATTR(mempool, S_IRUGO, mempool_show, NULL);
+
+static struct class omap_mmu_class = {
+       .name           = "mmu",
+};
+
+int omap_mmu_register(struct omap_mmu *mmu)
+{
+       int ret;
+
+       mmu->dev = device_create(&omap_mmu_class, NULL, 0, "%s", mmu->name);
+       if (unlikely(IS_ERR(mmu->dev)))
+               return PTR_ERR(mmu->dev);
+       dev_set_drvdata(mmu->dev, mmu);
+
+       mmu->exmap_tbl = kcalloc(mmu->nr_tlb_entries, sizeof(struct exmap_tbl),
+                                GFP_KERNEL);
+       if (!mmu->exmap_tbl)
+               return -ENOMEM;
+
+       mmu->twl_mm = mm_alloc();
+       if (!mmu->twl_mm) {
+               ret = -ENOMEM;
+               goto err_mm_alloc;
+       }
+
+       init_rwsem(&mmu->exmap_sem);
+
+       ret = omap_mmu_init(mmu);
+       if (unlikely(ret))
+               goto err_mmu_init;
+
+       ret = device_create_file(mmu->dev, &dev_attr_mmu);
+       if (unlikely(ret))
+               goto err_dev_create_mmu;
+       ret = device_create_file(mmu->dev, &dev_attr_exmap);
+       if (unlikely(ret))
+               goto err_dev_create_exmap;
+
+       if (likely(mmu->membase)) {
+               dev_attr_mem.size = mmu->memsize;
+               ret = device_create_bin_file(mmu->dev,
+                                            &dev_attr_mem);
+               if (unlikely(ret))
+                       goto err_bin_create_mem;
+       }
+       return 0;
+
+err_bin_create_mem:
+       device_remove_file(mmu->dev, &dev_attr_exmap);
+err_dev_create_exmap:
+       device_remove_file(mmu->dev, &dev_attr_mmu);
+err_dev_create_mmu:
+       omap_mmu_shutdown(mmu);
+err_mmu_init:
+       kfree(mmu->twl_mm);
+       mmu->twl_mm = NULL;
+err_mm_alloc:
+       kfree(mmu->exmap_tbl);
+       mmu->exmap_tbl = NULL;
+       device_unregister(mmu->dev);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(omap_mmu_register);
+
+void omap_mmu_unregister(struct omap_mmu *mmu)
+{
+       omap_mmu_shutdown(mmu);
+       omap_mmu_kmem_release();
+
+       device_remove_file(mmu->dev, &dev_attr_mmu);
+       device_remove_file(mmu->dev, &dev_attr_exmap);
+
+       if (likely(mmu->membase))
+               device_remove_bin_file(mmu->dev, &dev_attr_mem);
+
+       device_unregister(mmu->dev);
+
+       kfree(mmu->exmap_tbl);
+       mmu->exmap_tbl = NULL;
+
+       if (mmu->twl_mm) {
+               __mmdrop(mmu->twl_mm);
+               mmu->twl_mm = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(omap_mmu_unregister);
+
+static int __init omap_mmu_class_init(void)
+{
+       int ret = class_register(&omap_mmu_class);
+       if (!ret)
+               ret = class_create_file(&omap_mmu_class, &class_attr_mempool);
+
+       return ret;
+}
+
+static void __exit omap_mmu_class_exit(void)
+{
+       class_remove_file(&omap_mmu_class, &class_attr_mempool);
+       class_unregister(&omap_mmu_class);
+}
+
+subsys_initcall(omap_mmu_class_init);
+module_exit(omap_mmu_class_exit);
+
+MODULE_LICENSE("GPL");
index ac67eeb6ca6a6266428ad8c74a906af7df4469b9..853048d12bac25c034de871102c9d42c9dfae7ce 100644 (file)
@@ -271,7 +271,7 @@ int __init omap1_sram_init(void)
 #define omap1_sram_init()      do {} while (0)
 #endif
 
-#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#if defined(CONFIG_ARCH_OMAP2)
 
 static void (*_omap2_sram_ddr_init)(u32 *slow_dll_ctrl, u32 fast_dll_ctrl,
                              u32 base_cs, u32 force_unlock);
@@ -352,60 +352,41 @@ static inline int omap243x_sram_init(void)
 
 #ifdef CONFIG_ARCH_OMAP3
 
-static u32 (*_omap2_sram_reprogram_gpmc)(u32 perf_level);
-u32 omap2_sram_reprogram_gpmc(u32 perf_level)
-{
-       if (!_omap2_sram_reprogram_gpmc)
+static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl,
+                                             u32 sdrc_actim_ctrla,
+                                             u32 sdrc_actim_ctrlb,
+                                             u32 m2);
+u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla,
+                             u32 sdrc_actim_ctrlb, u32 m2)
+ {
+       if (!_omap3_sram_configure_core_dpll)
                omap_sram_error();
 
-       return _omap2_sram_reprogram_gpmc(perf_level);
-}
-
-static u32 (*_omap2_sram_configure_core_dpll)(u32 m, u32 n,
-                                               u32 freqsel, u32 m2);
-u32 omap2_sram_configure_core_dpll(u32 m, u32 n, u32 freqsel, u32 m2)
-{
-       if (!_omap2_sram_configure_core_dpll)
-               omap_sram_error();
-
-       return _omap2_sram_configure_core_dpll(m, n, freqsel, m2);
-}
+       return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl,
+                                              sdrc_actim_ctrla,
+                                              sdrc_actim_ctrlb, m2);
+ }
 
 /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */
 void restore_sram_functions(void)
 {
        omap_sram_ceil = omap_sram_base + omap_sram_size;
 
-       _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc,
-               omap34xx_sram_reprogram_gpmc_sz);
-
-       _omap2_sram_configure_core_dpll =
-                       omap_sram_push(omap34xx_sram_configure_core_dpll,
-                                       omap34xx_sram_configure_core_dpll_sz);
+       _omap3_sram_configure_core_dpll =
+               omap_sram_push(omap3_sram_configure_core_dpll,
+                              omap3_sram_configure_core_dpll_sz);
 }
 
-int __init omap34xx_sram_init(void)
+int __init omap3_sram_init(void)
 {
-       _omap2_sram_ddr_init = omap_sram_push(omap34xx_sram_ddr_init,
-                                       omap34xx_sram_ddr_init_sz);
-
-       _omap2_sram_reprogram_sdrc = omap_sram_push(omap34xx_sram_reprogram_sdrc,
-                                       omap34xx_sram_reprogram_sdrc_sz);
-
-       _omap2_set_prcm = omap_sram_push(omap34xx_sram_set_prcm,
-                                       omap34xx_sram_set_prcm_sz);
-
-       _omap2_sram_reprogram_gpmc = omap_sram_push(omap34xx_sram_reprogram_gpmc,
-                                       omap34xx_sram_reprogram_gpmc_sz);
-
-       _omap2_sram_configure_core_dpll =
-                               omap_sram_push(omap34xx_sram_configure_core_dpll,
-                                       omap34xx_sram_configure_core_dpll_sz);
+       _omap3_sram_configure_core_dpll =
+               omap_sram_push(omap3_sram_configure_core_dpll,
+                              omap3_sram_configure_core_dpll_sz);
 
        return 0;
 }
 #else
-static inline int omap34xx_sram_init(void)
+static inline int omap3_sram_init(void)
 {
        return 0;
 }
@@ -423,7 +404,7 @@ int __init omap_sram_init(void)
        else if (cpu_is_omap2430())
                omap243x_sram_init();
        else if (cpu_is_omap34xx())
-               omap34xx_sram_init();
+               omap3_sram_init();
 
        return 0;
 }
index 2735bde73475c5f840c2d52266fd47e54b730bcd..39cfe4034d1aeab2c795de77af08bb4bc599a4a3 100644 (file)
@@ -31,9 +31,15 @@ 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-y                          += base/ block/ misc/ mfd/ net/ media/ cbus/
+obj-y                          += i2c/
+obj-y                          += cbus/
+obj-$(CONFIG_ARCH_OMAP)                += dsp/dspgateway/
 obj-$(CONFIG_NUBUS)            += nubus/
 obj-$(CONFIG_ATM)              += atm/
 obj-y                          += macintosh/
@@ -60,12 +66,10 @@ obj-$(CONFIG_USB)           += usb/
 obj-$(CONFIG_USB_MUSB_HDRC)    += usb/musb/
 obj-$(CONFIG_PCI)              += usb/
 obj-$(CONFIG_USB_GADGET)       += usb/gadget/
-obj-$(CONFIG_SERIO)            += input/serio/
 obj-$(CONFIG_GAMEPORT)         += input/gameport/
 obj-$(CONFIG_INPUT)            += input/
 obj-$(CONFIG_I2O)              += message/
 obj-$(CONFIG_RTC_LIB)          += rtc/
-obj-y                          += i2c/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_POWER_SUPPLY)     += power/
 obj-$(CONFIG_HWMON)            += hwmon/
index 7cb4029a5375a774ed9c0cc888284d37330b1b17..6bb2027d595e01076c41a0ec8c8ebabab8b7ea6d 100644 (file)
@@ -181,6 +181,27 @@ config BT_HCIBTUART
          Say Y here to compile support for HCI UART devices into the
          kernel or say M to compile it as module (btuart_cs).
 
+config BT_HCIBRF6150
+       tristate "HCI TI BRF6150 driver with H4 extensions"
+       depends on BT && ARCH_OMAP
+       help
+         Bluetooth HCI driver for TI BRF6150 with H4 extensions.
+         This driver provides support for BRF6150 Bluetooth chip 
+         with vendor-specific H4 extensions.
+
+         Say Y here to compile support for TI BRF6150 devices into the
+         kernel or say M to compile it as module (brf6150).
+
+config BT_HCIH4P
+       tristate "HCI driver with H4 Nokia extensions"
+       depends on BT && ARCH_OMAP 
+       help 
+         Bluetooth HCI driver with H4 extensions.  This driver provides
+         support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+         Say Y here to compile support for h4 extended devices into the kernel
+         or say M to compile it as module (hci_h4p).
+
 config BT_HCIVHCI
        tristate "HCI VHCI (Virtual HCI device) driver"
        help
index 77444afbf107281de422a950d1e0a4ac63469cc0..0fab1f0318dfb1ce26b8c6f58cf30c461e72fbc5 100644 (file)
@@ -12,6 +12,8 @@ obj-$(CONFIG_BT_HCIDTL1)      += dtl1_cs.o
 obj-$(CONFIG_BT_HCIBT3C)       += bt3c_cs.o
 obj-$(CONFIG_BT_HCIBLUECARD)   += bluecard_cs.o
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
+obj-$(CONFIG_BT_HCIBRF6150)    += brf6150.o
+obj-$(CONFIG_BT_HCIH4P)                += hci_h4p/
 
 obj-$(CONFIG_BT_HCIBTUSB)      += btusb.o
 obj-$(CONFIG_BT_HCIBTSDIO)     += btsdio.o
diff --git a/drivers/bluetooth/brf6150.c b/drivers/bluetooth/brf6150.c
new file mode 100644 (file)
index 0000000..476cc65
--- /dev/null
@@ -0,0 +1,1050 @@
+/*
+ *  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 <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/irqs.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "brf6150.h"
+
+#if 0
+#define NBT_DBG(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...)  printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#define PM_TIMEOUT (2000)
+
+static void brf6150_device_release(struct device *dev);
+static struct brf6150_info *exit_info;
+
+static struct platform_device brf6150_device = {
+       .name           = BT_DEVICE,
+       .id             = -1,
+       .num_resources  = 0,
+       .dev = {
+               .release = brf6150_device_release,
+       }
+};
+
+static struct device_driver brf6150_driver = {
+       .name           = BT_DRIVER,
+       .bus            = &platform_bus_type,
+};
+
+static inline void brf6150_outb(struct brf6150_info *info, unsigned int offset, u8 val)
+{
+       outb(val, info->uart_base + (offset << 2));
+}
+
+static inline u8 brf6150_inb(struct brf6150_info *info, unsigned int offset)
+{
+       return inb(info->uart_base + (offset << 2));
+}
+
+static void brf6150_set_rts(struct brf6150_info *info, int active)
+{
+       u8 b;
+
+       b = brf6150_inb(info, UART_MCR);
+       if (active)
+               b |= UART_MCR_RTS;
+       else
+               b &= ~UART_MCR_RTS;
+       brf6150_outb(info, UART_MCR, b);
+}
+
+static void brf6150_wait_for_cts(struct brf6150_info *info, int active,
+                                int timeout_ms)
+{
+       int okay;
+       unsigned long timeout;
+
+       okay = 0;
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       for (;;) {
+               int state;
+
+               state = brf6150_inb(info, UART_MSR) & UART_MSR_CTS;
+               if (active) {
+                       if (state)
+                               break;
+               } else {
+                       if (!state)
+                               break;
+               }
+               if (jiffies > timeout)
+                       break;
+       }
+}
+
+static inline void brf6150_set_auto_ctsrts(struct brf6150_info *info, int on)
+{
+       u8 lcr, b;
+
+       lcr = brf6150_inb(info, UART_LCR);
+       brf6150_outb(info, UART_LCR, 0xbf);
+       b = brf6150_inb(info, UART_EFR);
+       if (on)
+               b |= UART_EFR_CTS | UART_EFR_RTS;
+       else
+               b &= ~(UART_EFR_CTS | UART_EFR_RTS);
+       brf6150_outb(info, UART_EFR, b);
+       brf6150_outb(info, UART_LCR, lcr);
+}
+
+static inline void brf6150_enable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 1;
+       }
+}
+
+static inline void brf6150_disable_pm_rx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->rx_pm_enabled = 0;
+       }
+}
+
+static void brf6150_enable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               mod_timer(&info->pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+               info->tx_pm_enabled = 1;
+       }
+}
+
+static void brf6150_disable_pm_tx(struct brf6150_info *info)
+{
+       if (info->pm_enabled) {
+               info->tx_pm_enabled = 0;
+               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), IRQ_TYPE_NONE);
+       init_completion(&info->fw_completion);
+
+       clk_enable(info->uart_ck);
+
+       brf6150_init_uart(info);
+       brf6150_set_auto_ctsrts(info, 0);
+       brf6150_set_rts(info, 0);
+       brf6150_reset(info);
+       brf6150_wait_for_cts(info, 1, 10);
+       brf6150_set_rts(info, 1);
+       if (brf6150_send_negotiation(info)) {
+               brf6150_close_firmware(info);
+               return -1;
+       }
+
+       if (!wait_for_completion_interruptible_timeout(&info->init_completion, HZ)) {
+               brf6150_close_firmware(info);
+               clk_disable(info->uart_ck);
+               clear_bit(HCI_RUNNING, &hdev->flags);
+               return -1;
+       }
+       brf6150_set_auto_ctsrts(info, 1);
+
+       err = brf6150_send_firmware(info);
+       brf6150_close_firmware(info);
+       if (err < 0)
+               printk(KERN_ERR "brf6150: Sending firmware failed. Bluetooth won't work properly\n");
+
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_EDGE_BOTH);
+       info->pm_enabled = 1;
+       set_bit(HCI_RUNNING, &hdev->flags);
+       return 0;
+}
+
+static int brf6150_hci_close(struct hci_dev *hdev)
+{
+       struct brf6150_info *info = hdev->driver_data;
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       brf6150_hci_flush(hdev);
+       clk_disable(info->uart_ck);
+       del_timer_sync(&info->pm_timer);
+       omap_set_gpio_dataout(info->btinfo->bt_wakeup_gpio, 0);
+       set_irq_type(OMAP_GPIO_IRQ(info->btinfo->host_wakeup_gpio), IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static void brf6150_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int brf6150_hci_send_frame(struct sk_buff *skb)
+{
+       struct brf6150_info *info;
+       struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Frame for unknown device\n");
+               return -ENODEV;
+       }
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+               printk(KERN_WARNING "brf6150: Frame for non-running device\n");
+               return -EIO;
+       }
+
+       info = hdev->driver_data;
+
+       switch (bt_cb(skb)->pkt_type) {
+               case HCI_COMMAND_PKT:
+                       hdev->stat.cmd_tx++;
+                       break;
+               case HCI_ACLDATA_PKT:
+                       hdev->stat.acl_tx++;
+                       break;
+               case HCI_SCODATA_PKT:
+                       hdev->stat.sco_tx++;
+                       break;
+       };
+
+       /* Push frame type to skb */
+       clk_enable(info->uart_ck);
+       *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
+       skb_queue_tail(&info->txq, skb);
+
+       brf6150_disable_pm_tx(info);
+
+       return 0;
+}
+
+static int brf6150_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void brf6150_device_release(struct device *dev)
+{
+}
+
+static int brf6150_register_hdev(struct brf6150_info *info)
+{
+       struct hci_dev *hdev;
+
+       /* Initialize and register HCI device */
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               printk(KERN_WARNING "brf6150: Can't allocate memory for device\n");
+               return -ENOMEM;
+       }
+       info->hdev = hdev;
+
+       hdev->type = HCI_UART;
+       hdev->driver_data = info;
+
+       hdev->open = brf6150_hci_open;
+       hdev->close = brf6150_hci_close;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->flush = brf6150_hci_flush;
+       hdev->send = brf6150_hci_send_frame;
+       hdev->destruct = brf6150_hci_destruct;
+       hdev->ioctl = brf6150_hci_ioctl;
+
+       hdev->owner = THIS_MODULE;
+
+       if (hci_register_dev(hdev) < 0) {
+               printk(KERN_WARNING "brf6150: Can't register HCI device %s.\n", hdev->name);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init brf6150_init(void)
+{
+       struct brf6150_info *info;
+       int irq, err;
+
+       info = kmalloc(sizeof(struct brf6150_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       memset(info, 0, sizeof(struct brf6150_info));
+
+       brf6150_device.dev.driver_data = info;
+       init_completion(&info->init_completion);
+       init_completion(&info->fw_completion);
+       info->pm_enabled = 0;
+       info->rx_pm_enabled = 0;
+       info->tx_pm_enabled = 0;
+       info->garbage_bytes = 0;
+       tasklet_init(&info->tx_task, brf6150_tx_tasklet, (unsigned long)info);
+       spin_lock_init(&info->lock);
+       skb_queue_head_init(&info->txq);
+       init_timer(&info->pm_timer);
+       info->pm_timer.function = brf6150_pm_timer;
+       info->pm_timer.data = (unsigned long)info;
+       exit_info = NULL;
+
+       info->btinfo = omap_get_config(OMAP_TAG_NOKIA_BT, struct omap_bluetooth_config);
+       if (info->btinfo == NULL)
+               return -1;
+
+       NBT_DBG("RESET gpio: %d\n", info->btinfo->reset_gpio);
+       NBT_DBG("BTWU gpio: %d\n", info->btinfo->bt_wakeup_gpio);
+       NBT_DBG("HOSTWU gpio: %d\n", info->btinfo->host_wakeup_gpio);
+       NBT_DBG("Uart: %d\n", info->btinfo->bt_uart);
+       NBT_DBG("sysclk: %d\n", info->btinfo->bt_sysclk);
+
+       err = 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), IRQ_TYPE_NONE);
+
+       switch (info->btinfo->bt_uart) {
+       case 1:
+               irq = INT_UART1;
+               info->uart_ck = clk_get(NULL, "uart1_ck");
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART1_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       case 2:
+               irq = INT_UART2;
+               info->uart_ck = clk_get(NULL, "uart2_ck");
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART2_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       case 3:
+               irq = INT_UART3;
+               info->uart_ck = clk_get(NULL, "uart3_ck");
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART3_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       default:
+               printk(KERN_ERR "No uart defined\n");
+               goto cleanup;
+       }
+
+       info->irq = irq;
+       err = request_irq(irq, brf6150_interrupt, 0, "brf6150", (void *)info);
+       if (err < 0) {
+               printk(KERN_ERR "brf6150: unable to get IRQ %d\n", irq);
+               goto cleanup;
+       }
+
+       err = request_irq(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..e8b2988
--- /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 <mach/board.h>
+
+#ifndef __DRIVERS_BLUETOOTH_BRF6150_H
+#define __DRIVERS_BLUETOOTH_BRF6150_H
+
+#define UART_SYSC_OMAP_RESET   0x02
+#define UART_SYSS_RESETDONE    0x01
+#define UART_OMAP_SCR_EMPTY_THR        0x08
+#define UART_OMAP_SCR_WAKEUP   0x10
+#define UART_OMAP_SSR_WAKEUP   0x02
+#define UART_OMAP_SSR_TXFULL   0x01
+
+struct brf6150_info {
+       struct hci_dev *hdev;
+       spinlock_t lock;
+
+       struct clk *uart_ck;
+       unsigned long uart_base;
+       unsigned int irq;
+
+       struct sk_buff_head txq;
+       struct sk_buff *rx_skb;
+       const struct omap_bluetooth_config *btinfo;
+       const struct firmware *fw_entry;
+       int fw_pos;
+       int fw_error;
+       struct completion fw_completion;
+       struct completion init_completion;
+       struct tasklet_struct tx_task;
+       long rx_count;
+       unsigned long garbage_bytes;
+       unsigned long rx_state;
+       int pm_enabled;
+       int rx_pm_enabled;
+       int tx_pm_enabled;
+       struct timer_list pm_timer;
+};
+
+#define BT_DEVICE "nokia_btuart"
+#define BT_DRIVER "nokia_btuart"
+
+#define MAX_BAUD_RATE          921600
+#define UART_CLOCK             48000000
+#define BT_INIT_DIVIDER                320
+#define BT_BAUDRATE_DIVIDER    384000000
+#define BT_SYSCLK_DIV          1000
+#define INIT_SPEED             120000
+
+#define H4_TYPE_SIZE           1
+
+/* H4+ packet types */
+#define H4_CMD_PKT             0x01
+#define H4_ACL_PKT             0x02
+#define H4_SCO_PKT             0x03
+#define H4_EVT_PKT             0x04
+#define H4_NEG_PKT             0x06
+#define H4_ALIVE_PKT           0x07
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE      1
+#define WAIT_FOR_HEADER                2
+#define WAIT_FOR_DATA          3
+
+struct hci_fw_event {
+       struct hci_event_hdr hev;
+       struct hci_ev_cmd_complete cmd;
+       __u8 status;
+} __attribute__ ((packed));
+
+#endif /* __DRIVERS_BLUETOOTH_BRF6150_H */
diff --git a/drivers/bluetooth/hci_h4p/Makefile b/drivers/bluetooth/hci_h4p/Makefile
new file mode 100644 (file)
index 0000000..07608a4
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P)                += hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o sysfs.o fw-ti.o fw-csr.o
diff --git a/drivers/bluetooth/hci_h4p/core.c b/drivers/bluetooth/hci_h4p/core.c
new file mode 100644 (file)
index 0000000..005e652
--- /dev/null
@@ -0,0 +1,1013 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/pm.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+#define PM_TIMEOUT 200
+
+/* This should be used in function that cannot release clocks */
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->clocks_lock, flags);
+       if (enable && !*clock) {
+               NBT_DBG_POWER("Enabling %p\n", clock);
+               clk_enable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+               if (cpu_is_omap24xx()) {
+                       clk_enable(info->uart_iclk);
+                       omap2_block_sleep();
+               }
+#endif
+       }
+       if (!enable && *clock) {
+               NBT_DBG_POWER("Disabling %p\n", clock);
+               clk_disable(info->uart_fclk);
+#ifdef CONFIG_ARCH_OMAP2
+               if (cpu_is_omap24xx()) {
+                       clk_disable(info->uart_iclk);
+                       omap2_allow_sleep();
+               }
+#endif
+       }
+
+       *clock = enable;
+       spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+       NBT_DBG_POWER("\n");
+
+       if (!info->pm_enabled)
+               return;
+
+       mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+       NBT_DBG_POWER("\n");
+
+       if (!info->pm_enabled)
+               return;
+
+       del_timer_sync(&info->tx_pm_timer);
+       if (info->tx_pm_enabled) {
+               info->tx_pm_enabled = 0;
+               hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+               omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+       }
+}
+
+static void hci_h4p_tx_pm_timer(unsigned long data)
+{
+       struct hci_h4p_info *info;
+
+       NBT_DBG_POWER("\n");
+
+       info = (struct hci_h4p_info *)data;
+
+       if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+               omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+               hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+               info->tx_pm_enabled = 1;
+       }
+       else {
+               mod_timer(&info->tx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+       }
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+       if (!info->pm_enabled)
+               return;
+
+       mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+       unsigned long flags;
+
+       if (!info->pm_enabled)
+               return;
+
+       del_timer_sync(&info->rx_pm_timer);
+       spin_lock_irqsave(&info->lock, flags);
+       if (info->rx_pm_enabled) {
+               hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+               __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+               info->rx_pm_enabled = 0;
+       }
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hci_h4p_rx_pm_timer(unsigned long data)
+{
+       unsigned long flags;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       spin_lock_irqsave(&info->lock, flags);
+       if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+               __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+               hci_h4p_set_rts(info, 0);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+               hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+               info->rx_pm_enabled = 1;
+       }
+       else {
+               mod_timer(&info->rx_pm_timer, jiffies + msecs_to_jiffies(PM_TIMEOUT));
+       }
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+       NBT_DBG("Sending alive packet\n");
+
+       if (!info->alive_cmd_skb)
+               return -EINVAL;
+
+       /* Keep reference to buffer so we can reuse it */
+       info->alive_cmd_skb = skb_get(info->alive_cmd_skb);
+
+       skb_queue_tail(&info->txq, info->alive_cmd_skb);
+       tasklet_schedule(&info->tx_task);
+
+       NBT_DBG("Alive packet sent\n");
+
+       return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       NBT_DBG("Received alive packet\n");
+       if (skb->data[1] == 0xCC) {
+               complete(&info->init_completion);
+       }
+
+       kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       NBT_DBG("Sending negotiation..\n");
+
+       hci_h4p_change_speed(info, INIT_SPEED);
+
+       info->init_error = 0;
+       init_completion(&info->init_completion);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+                               msecs_to_jiffies(1000))) 
+               return -ETIMEDOUT;
+
+       NBT_DBG("Negotiation sent\n");
+       return info->init_error;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+                                      struct sk_buff *skb)
+{
+       int err = 0;
+
+       if (skb->data[1] == 0x20) {
+               /* Change to operational settings */
+               hci_h4p_set_rts(info, 0);
+
+               err = hci_h4p_wait_for_cts(info, 0, 100);
+               if (err < 0)
+                       goto neg_ret;
+
+               hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+               err = hci_h4p_wait_for_cts(info, 1, 100);
+               if (err < 0)
+                       goto neg_ret;
+
+               hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+
+               err = hci_h4p_send_alive_packet(info);
+               if (err < 0)
+                       goto neg_ret;
+       } else {
+               dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+               err = -EINVAL;
+               goto neg_ret;
+       }
+
+       kfree_skb(skb);
+       return;
+
+neg_ret:
+       info->init_error = err;
+       complete(&info->init_completion);
+       kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+       long retval;
+
+       switch (pkt_type) {
+       case H4_EVT_PKT:
+               retval = HCI_EVENT_HDR_SIZE;
+               break;
+       case H4_ACL_PKT:
+               retval = HCI_ACL_HDR_SIZE;
+               break;
+       case H4_SCO_PKT:
+               retval = HCI_SCO_HDR_SIZE;
+               break;
+       case H4_NEG_PKT:
+               retval = 11;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 3;
+               break;
+       default:
+               dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+               retval = -1;
+               break;
+       }
+
+       return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+                                        struct sk_buff *skb)
+{
+       long retval = -1;
+       struct hci_event_hdr *evt_hdr;
+       struct hci_acl_hdr *acl_hdr;
+       struct hci_sco_hdr *sco_hdr;
+
+       switch (bt_cb(skb)->pkt_type) {
+       case H4_EVT_PKT:
+               evt_hdr = (struct hci_event_hdr *)skb->data;
+               retval = evt_hdr->plen;
+               break;
+       case H4_ACL_PKT:
+               acl_hdr = (struct hci_acl_hdr *)skb->data;
+               retval = le16_to_cpu(acl_hdr->dlen);
+               break;
+       case H4_SCO_PKT:
+               sco_hdr = (struct hci_sco_hdr *)skb->data;
+               retval = sco_hdr->dlen;
+               break;
+       case H4_NEG_PKT:
+               retval = 0;
+               break;
+       case H4_ALIVE_PKT:
+               retval = 0;
+               break;
+       }
+
+       return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+                                     struct sk_buff *skb)
+{
+
+       if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+               NBT_DBG("fw_event\n");
+               hci_h4p_parse_fw_event(info, skb);
+       } else {
+               hci_recv_frame(skb);
+               NBT_DBG("Frame sent to upper layer\n");
+       }
+}
+
+static void hci_h4p_rx_tasklet(unsigned long data)
+{
+       u8 byte;
+       unsigned long flags;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       NBT_DBG("tasklet woke up\n");
+       NBT_DBG_TRANSFER("rx_tasklet woke up\ndata ");
+
+       while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+               byte = hci_h4p_inb(info, UART_RX);
+               if (info->garbage_bytes) {
+                       info->garbage_bytes--;
+                       continue;
+               }
+               if (info->rx_skb == NULL) {
+                       info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC | GFP_DMA);
+                       if (!info->rx_skb) {
+                               dev_err(info->dev, "Can't allocate memory for new packet\n");
+                               goto finish_task;
+                       }
+                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                       info->rx_skb->dev = (void *)info->hdev;
+               }
+               info->hdev->stat.byte_rx++;
+               NBT_DBG_TRANSFER_NF("0x%.2x  ", byte);
+               switch (info->rx_state) {
+               case WAIT_FOR_PKT_TYPE:
+                       bt_cb(info->rx_skb)->pkt_type = byte;
+                       info->rx_count = hci_h4p_get_hdr_len(info, byte);
+                       if (info->rx_count < 0) {
+                               info->hdev->stat.err_rx++;
+                               kfree_skb(info->rx_skb);
+                               info->rx_skb = NULL;
+                       } else {
+                               info->rx_state = WAIT_FOR_HEADER;
+                       }
+                       break;
+               case WAIT_FOR_HEADER:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               info->rx_count = hci_h4p_get_data_len(info, info->rx_skb);
+                               if (info->rx_count > skb_tailroom(info->rx_skb)) {
+                                       dev_err(info->dev, "Frame is %ld bytes too long.\n",
+                                              info->rx_count - skb_tailroom(info->rx_skb));
+                                       kfree_skb(info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->garbage_bytes = info->rx_count - skb_tailroom(info->rx_skb);
+                                       break;
+                               }
+                               info->rx_state = WAIT_FOR_DATA;
+
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+                                       hci_h4p_negotiation_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                                       goto finish_task;
+                               }
+                               if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+                                       hci_h4p_alive_packet(info, info->rx_skb);
+                                       info->rx_skb = NULL;
+                                       info->rx_state = WAIT_FOR_PKT_TYPE;
+                                       goto finish_task;
+                               }
+                       }
+                       break;
+               case WAIT_FOR_DATA:
+                       info->rx_count--;
+                       *skb_put(info->rx_skb, 1) = byte;
+                       if (info->rx_count == 0) {
+                               /* H4+ devices should allways send word aligned packets */
+                               if (!(info->rx_skb->len % 2)) {
+                                       info->garbage_bytes++;
+                               }
+                               hci_h4p_recv_frame(info, info->rx_skb);
+                               info->rx_skb = NULL;
+                       }
+                       break;
+               default:
+                       WARN_ON(1);
+                       break;
+               }
+       }
+
+finish_task:
+       spin_lock_irqsave(&info->lock, flags);
+       hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_RDI);
+       spin_unlock_irqrestore(&info->lock, flags);
+
+       NBT_DBG_TRANSFER_NF("\n");
+       NBT_DBG("rx_ended\n");
+}
+
+static void hci_h4p_tx_tasklet(unsigned long data)
+{
+       unsigned int sent = 0;
+       unsigned long flags;
+       struct sk_buff *skb;
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+       NBT_DBG("tasklet woke up\n");
+       NBT_DBG_TRANSFER("tx_tasklet woke up\n data ");
+
+       skb = skb_dequeue(&info->txq);
+       if (!skb) {
+               /* No data in buffer */
+               NBT_DBG("skb ready\n");
+               hci_h4p_disable_tx(info);
+               return;
+       }
+
+       /* Copy data to tx fifo */
+       while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+              (sent < skb->len)) {
+               NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+               hci_h4p_outb(info, UART_TX, skb->data[sent]);
+               sent++;
+       }
+
+       info->hdev->stat.byte_tx += sent;
+       NBT_DBG_TRANSFER_NF("\n");
+       if (skb->len == sent) {
+               kfree_skb(skb);
+       } else {
+               skb_pull(skb, sent);
+               skb_queue_head(&info->txq, skb);
+       }
+
+       spin_lock_irqsave(&info->lock, flags);
+       hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) | UART_IER_THRI);
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+       u8 iir, msr;
+       int ret;
+       unsigned long flags;
+
+       ret = IRQ_NONE;
+
+       iir = hci_h4p_inb(info, UART_IIR);
+       if (iir & UART_IIR_NO_INT) {
+               dev_err(info->dev, "Interrupt but no reason irq 0x%.2x\n", iir);
+               return IRQ_HANDLED;
+       }
+
+       NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+       iir &= UART_IIR_ID;
+
+       if (iir == UART_IIR_MSI) {
+               msr = hci_h4p_inb(info, UART_MSR);
+               ret = IRQ_HANDLED;
+       }
+       if (iir == UART_IIR_RLSI) {
+               hci_h4p_inb(info, UART_RX);
+               hci_h4p_inb(info, UART_LSR);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_RDI) {
+               spin_lock_irqsave(&info->lock, flags);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_RDI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->rx_task);
+               ret = IRQ_HANDLED;
+       }
+
+       if (iir == UART_IIR_THRI) {
+               spin_lock_irqsave(&info->lock, flags);
+               hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) & ~UART_IER_THRI);
+               spin_unlock_irqrestore(&info->lock, flags);
+               tasklet_schedule(&info->tx_task);
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+       struct hci_h4p_info *info = dev_inst;
+       int should_wakeup;
+       struct hci_dev *hdev;
+
+       if (!info->hdev)
+               return IRQ_HANDLED;
+
+       hdev = info->hdev;
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               return IRQ_HANDLED;
+
+       should_wakeup = omap_get_gpio_datain(info->host_wakeup_gpio);
+       NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+       if (should_wakeup) {
+               hci_h4p_enable_rx(info);
+       } else {
+               hci_h4p_disable_rx(info);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+       int err;
+
+       hci_h4p_init_uart(info);
+       hci_h4p_set_rts(info, 0);
+
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       msleep(100);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 1);
+       omap_set_gpio_dataout(info->reset_gpio, 1);
+       msleep(100);
+
+       err = hci_h4p_wait_for_cts(info, 1, 10);
+       if (err < 0) {
+               dev_err(info->dev, "No cts from bt chip\n");
+               return err;
+       }
+
+       hci_h4p_set_rts(info, 1);
+
+       return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info;
+       info = hdev->driver_data;
+
+       skb_queue_purge(&info->txq);
+
+       return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info;
+       int err;
+       struct sk_buff *neg_cmd_skb;
+       struct sk_buff_head fw_queue;
+
+       info = hdev->driver_data;
+
+       if (test_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       skb_queue_head_init(&fw_queue);
+       err = hci_h4p_read_fw(info, &fw_queue);
+       if (err < 0) {
+               dev_err(info->dev, "Cannot read firmware\n");
+               return err;
+       }
+       neg_cmd_skb = skb_dequeue(&fw_queue);
+       if (!neg_cmd_skb) {
+               err = -EPROTO;
+               goto err_clean;
+       }
+       info->alive_cmd_skb = skb_dequeue(&fw_queue);
+       if (!info->alive_cmd_skb) {
+               err = -EPROTO;
+               goto err_clean;
+       }
+
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+
+       tasklet_enable(&info->tx_task);
+       tasklet_enable(&info->rx_task);
+       info->rx_state = WAIT_FOR_PKT_TYPE;
+       info->rx_count = 0;
+       info->garbage_bytes = 0;
+       info->rx_skb = NULL;
+       info->pm_enabled = 0;
+       init_completion(&info->fw_completion);
+
+       err = hci_h4p_reset(info);
+       if (err < 0)
+               goto err_clean;
+
+       err = hci_h4p_send_negotiation(info, neg_cmd_skb);
+       neg_cmd_skb = NULL;
+       if (err < 0)
+               goto err_clean;
+
+       err = hci_h4p_send_fw(info, &fw_queue);
+       if (err < 0) {
+               dev_err(info->dev, "Sending firmware failed.\n");
+               goto err_clean;
+       }
+
+       kfree_skb(info->alive_cmd_skb);
+       info->alive_cmd_skb = NULL;
+       info->pm_enabled = 1;
+       info->tx_pm_enabled = 1;
+       info->rx_pm_enabled = 0;
+       set_bit(HCI_RUNNING, &hdev->flags);
+
+       NBT_DBG("hci up and running\n");
+       return 0;
+
+err_clean:
+       hci_h4p_hci_flush(hdev);
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       hci_h4p_reset_uart(info);
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+       skb_queue_purge(&fw_queue);
+       kfree_skb(neg_cmd_skb);
+       neg_cmd_skb = NULL;
+       kfree_skb(info->alive_cmd_skb);
+       info->alive_cmd_skb = NULL;
+       kfree_skb(info->rx_skb);
+
+       return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+       struct hci_h4p_info *info = hdev->driver_data;
+
+       if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+               return 0;
+
+       hci_h4p_hci_flush(hdev);
+       del_timer_sync(&info->tx_pm_timer);
+       del_timer_sync(&info->rx_pm_timer);
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+       hci_h4p_reset_uart(info);
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+       hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_set_gpio_dataout(info->bt_wakeup_gpio, 0);
+       kfree_skb(info->rx_skb);
+
+       return 0;
+}
+
+static void hci_h4p_hci_destruct(struct hci_dev *hdev)
+{
+}
+
+static int hci_h4p_hci_send_frame(struct sk_buff *skb)
+{
+       struct hci_h4p_info *info;
+       struct hci_dev *hdev = (struct hci_dev *)skb->dev;
+       int err = 0;
+
+       if (!hdev) {
+               printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+               return -ENODEV;
+       }
+
+       NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+       info = hdev->driver_data;
+
+       if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+               dev_warn(info->dev, "Frame for non-running device\n");
+               return -EIO;
+       }
+
+       switch (bt_cb(skb)->pkt_type) {
+       case HCI_COMMAND_PKT:
+               hdev->stat.cmd_tx++;
+               break;
+       case HCI_ACLDATA_PKT:
+               hdev->stat.acl_tx++;
+               break;
+       case HCI_SCODATA_PKT:
+               hdev->stat.sco_tx++;
+               break;
+       }
+
+       /* Push frame type to skb */
+       *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+       /* We should allways send word aligned data to h4+ devices */
+       if (skb->len % 2) {
+               err = skb_pad(skb, 1);
+       }
+       if (err)
+               return err;
+
+       hci_h4p_enable_tx(info);
+       skb_queue_tail(&info->txq, skb);
+       tasklet_schedule(&info->tx_task);
+
+       return 0;
+}
+
+static int hci_h4p_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+       struct hci_dev *hdev;
+
+       /* Initialize and register HCI device */
+
+       hdev = hci_alloc_dev();
+       if (!hdev) {
+               dev_err(info->dev, "Can't allocate memory for device\n");
+               return -ENOMEM;
+       }
+       info->hdev = hdev;
+
+       hdev->type = HCI_UART;
+       hdev->driver_data = info;
+
+       hdev->open = hci_h4p_hci_open;
+       hdev->close = hci_h4p_hci_close;
+       hdev->flush = hci_h4p_hci_flush;
+       hdev->send = hci_h4p_hci_send_frame;
+       hdev->destruct = hci_h4p_hci_destruct;
+       hdev->ioctl = hci_h4p_hci_ioctl;
+
+       hdev->owner = THIS_MODULE;
+
+       if (hci_register_dev(hdev) < 0) {
+               dev_err(info->dev, "hci_h4p: Can't register HCI device %s.\n", hdev->name);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+       struct omap_bluetooth_config *bt_config;
+       struct hci_h4p_info *info;
+       int irq, err;
+
+       dev_info(&pdev->dev, "Registering HCI H4P device\n");
+       info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->dev = &pdev->dev;
+       info->pm_enabled = 0;
+       info->tx_pm_enabled = 0;
+       info->rx_pm_enabled = 0;
+       info->garbage_bytes = 0;
+       info->tx_clocks_en = 0;
+       info->rx_clocks_en = 0;
+       tasklet_init(&info->tx_task, hci_h4p_tx_tasklet, (unsigned long)info);
+       tasklet_init(&info->rx_task, hci_h4p_rx_tasklet, (unsigned long)info);
+       /* hci_h4p_hci_open assumes that tasklet is disabled in startup */
+       tasklet_disable(&info->tx_task);
+       tasklet_disable(&info->rx_task);
+       spin_lock_init(&info->lock);
+       spin_lock_init(&info->clocks_lock);
+       skb_queue_head_init(&info->txq);
+       init_timer(&info->tx_pm_timer);
+       info->tx_pm_timer.function = hci_h4p_tx_pm_timer;
+       info->tx_pm_timer.data = (unsigned long)info;
+       init_timer(&info->rx_pm_timer);
+       info->rx_pm_timer.function = hci_h4p_rx_pm_timer;
+       info->rx_pm_timer.data = (unsigned long)info;
+
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+               return -ENODATA;
+       }
+
+       bt_config = pdev->dev.platform_data;
+       info->chip_type = bt_config->chip_type;
+       info->bt_wakeup_gpio = bt_config->bt_wakeup_gpio;
+       info->host_wakeup_gpio = bt_config->host_wakeup_gpio;
+       info->reset_gpio = bt_config->reset_gpio;
+       info->bt_sysclk = bt_config->bt_sysclk;
+
+       NBT_DBG("RESET gpio: %d\n", info->reset_gpio);
+       NBT_DBG("BTWU gpio: %d\n", info->bt_wakeup_gpio);
+       NBT_DBG("HOSTWU gpio: %d\n", info->host_wakeup_gpio);
+       NBT_DBG("Uart: %d\n", bt_config->bt_uart);
+       NBT_DBG("sysclk: %d\n", info->bt_sysclk);
+
+       err = omap_request_gpio(info->reset_gpio);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+                       info->reset_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       err = omap_request_gpio(info->bt_wakeup_gpio);
+       if (err < 0)
+       {
+               dev_err(info->dev, "Cannot get GPIO line 0x%d",
+                       info->bt_wakeup_gpio);
+               omap_free_gpio(info->reset_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       err = omap_request_gpio(info->host_wakeup_gpio);
+       if (err < 0)
+       {
+               dev_err(info->dev, "Cannot get GPIO line %d",
+                      info->host_wakeup_gpio);
+               omap_free_gpio(info->reset_gpio);
+               omap_free_gpio(info->bt_wakeup_gpio);
+               kfree(info);
+               goto cleanup;
+       }
+
+       omap_set_gpio_direction(info->reset_gpio, 0);
+       omap_set_gpio_direction(info->bt_wakeup_gpio, 0);
+       omap_set_gpio_direction(info->host_wakeup_gpio, 1);
+
+       switch (bt_config->bt_uart) {
+       case 1:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART1;
+                       info->uart_fclk = clk_get(NULL, "uart1_ck");
+               } else if (cpu_is_omap24xx()) {
+                       irq = INT_24XX_UART1_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart1_ick");
+                       info->uart_fclk = clk_get(NULL, "uart1_fck");
+               }
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART1_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       case 2:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART2;
+                       info->uart_fclk = clk_get(NULL, "uart2_ck");
+               } else {
+                       irq = INT_24XX_UART2_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart2_ick");
+                       info->uart_fclk = clk_get(NULL, "uart2_fck");
+               }
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART2_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       case 3:
+               if (cpu_is_omap16xx()) {
+                       irq = INT_UART3;
+                       info->uart_fclk = clk_get(NULL, "uart3_ck");
+               } else {
+                       irq = INT_24XX_UART3_IRQ;
+                       info->uart_iclk = clk_get(NULL, "uart3_ick");
+                       info->uart_fclk = clk_get(NULL, "uart3_fck");
+               }
+               /* FIXME: Use platform_get_resource for the port */
+               info->uart_base = ioremap(OMAP_UART3_BASE, 0x16);
+               if (!info->uart_base)
+                       goto cleanup;
+               break;
+       default:
+               dev_err(info->dev, "No uart defined\n");
+               goto cleanup;
+       }
+
+       info->irq = irq;
+       err = request_irq(irq, hci_h4p_interrupt, 0, "hci_h4p", (void *)info);
+       if (err < 0) {
+               dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", irq);
+               goto cleanup;
+       }
+
+       err = request_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio),
+                         hci_h4p_wakeup_interrupt,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                         "hci_h4p_wkup", (void *)info);
+       if (err < 0) {
+               dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+                         OMAP_GPIO_IRQ(info->host_wakeup_gpio));
+               free_irq(irq, (void *)info);
+               goto cleanup;
+       }
+
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+       hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_CTS | UART_EFR_RTS);
+       err = hci_h4p_init_uart(info);
+       if (err < 0)
+               goto cleanup_irq;
+       err = hci_h4p_reset(info);
+       if (err < 0)
+               goto cleanup_irq;
+       err = hci_h4p_wait_for_cts(info, 1, 10);
+       if (err < 0)
+               goto cleanup_irq;
+       hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+       platform_set_drvdata(pdev, info);
+       err = hci_h4p_sysfs_create_files(info->dev);
+       if (err < 0)
+               goto cleanup_irq;
+
+       if (hci_h4p_register_hdev(info) < 0) {
+               dev_err(info->dev, "failed to register hci_h4p hci device\n");
+               goto cleanup_irq;
+       }
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+
+       return 0;
+
+cleanup_irq:
+       free_irq(irq, (void *)info);
+       free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *)info);
+cleanup:
+       omap_set_gpio_dataout(info->reset_gpio, 0);
+       omap_free_gpio(info->reset_gpio);
+       omap_free_gpio(info->bt_wakeup_gpio);
+       omap_free_gpio(info->host_wakeup_gpio);
+       kfree(info);
+
+       return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *dev)
+{
+       struct hci_h4p_info *info;
+
+       info = platform_get_drvdata(dev);
+
+       hci_h4p_hci_close(info->hdev);
+       free_irq(OMAP_GPIO_IRQ(info->host_wakeup_gpio), (void *) info);
+       hci_free_dev(info->hdev);
+       omap_free_gpio(info->reset_gpio);
+       omap_free_gpio(info->bt_wakeup_gpio);
+       omap_free_gpio(info->host_wakeup_gpio);
+       free_irq(info->irq, (void *) info);
+       kfree(info);
+
+       return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+       .probe          = hci_h4p_probe,
+       .remove         = hci_h4p_remove,
+       .driver         = {
+               .name   = "hci_h4p",
+       },
+};
+
+static int __init hci_h4p_init(void)
+{
+       int err = 0;
+
+       /* Register the driver with LDM */
+       err = platform_driver_register(&hci_h4p_driver);
+       if (err < 0)
+               printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+       return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+       platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_DESCRIPTION("h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
diff --git a/drivers/bluetooth/hci_h4p/fw-csr.c b/drivers/bluetooth/hci_h4p/fw-csr.c
new file mode 100644 (file)
index 0000000..209aab2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       /* Check if this is fw packet */
+       if (skb->data[0] != 0xff) {
+               hci_recv_frame(skb);
+               return;
+       }
+
+       if (skb->data[11] || skb->data[12]) {
+               dev_err(info->dev, "Firmware sending command failed\n");
+               info->fw_error = -EPROTO;
+       }
+
+       kfree_skb(skb);
+       complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+                       struct sk_buff_head *fw_queue)
+{
+       struct sk_buff *skb;
+       unsigned int offset;
+       int retries, count, i;
+
+       info->fw_error = 0;
+
+       NBT_DBG_FW("Sending firmware\n");
+       skb = skb_dequeue(fw_queue);
+
+       if (!skb)
+               return -ENOMSG;
+
+       /* Check if this is bd_address packet */
+       if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+               offset = 21;
+               skb->data[offset + 1] = 0x00;
+               skb->data[offset + 5] = 0x00;
+               skb->data[offset + 7] = info->bdaddr[0];
+               skb->data[offset + 6] = info->bdaddr[1];
+               skb->data[offset + 4] = info->bdaddr[2];
+               skb->data[offset + 0] = info->bdaddr[3];
+               skb->data[offset + 3] = info->bdaddr[4];
+               skb->data[offset + 2] = info->bdaddr[5];
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (info->bdaddr[i] != 0x00)
+                       break;
+       }
+
+       if (i > 5) {
+               dev_info(info->dev, "Valid bluetooth address not found.\n");
+               kfree_skb(skb);
+               return -ENODEV;
+       }
+
+       for (count = 1; ; count++) {
+               NBT_DBG_FW("Sending firmware command %d\n", count);
+               init_completion(&info->fw_completion);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               skb = skb_dequeue(fw_queue);
+               if (!skb)
+                       break;
+
+               if (!wait_for_completion_timeout(&info->fw_completion,
+                                                msecs_to_jiffies(1000))) {
+                       dev_err(info->dev, "No reply to fw command\n");
+                       return -ETIMEDOUT;
+               }
+
+               if (info->fw_error) {
+                       dev_err(info->dev, "FW error\n");
+                       return -EPROTO;
+               }
+       };
+
+       /* Wait for chip warm reset */
+       retries = 100;
+       while ((!skb_queue_empty(&info->txq) ||
+              !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+              retries--) {
+               msleep(10);
+       }
+       if (!retries) {
+               dev_err(info->dev, "Transmitter not empty\n");
+               return -ETIMEDOUT;
+       }
+
+       hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+       if (hci_h4p_wait_for_cts(info, 1, 100)) {
+               dev_err(info->dev, "cts didn't go down after final speed change\n");
+               return -ETIMEDOUT;
+       }
+
+       retries = 100;
+       do {
+               init_completion(&info->init_completion);
+               hci_h4p_send_alive_packet(info);
+               retries--;
+       } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+                retries > 0);
+
+       if (!retries) {
+               dev_err(info->dev, "No alive reply after speed change\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-ti.c b/drivers/bluetooth/hci_h4p/fw-ti.c
new file mode 100644 (file)
index 0000000..b98b579
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+                                   struct sk_buff *skb)
+{
+       struct hci_fw_event *ev;
+       int err = 0;
+
+       if (bt_cb(skb)->pkt_type != H4_EVT_PKT) {
+               dev_err(info->dev, "Got non event fw packet.\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+       ev = (struct hci_fw_event *)skb->data;
+       if (ev->hev.evt != HCI_EV_CMD_COMPLETE) {
+               dev_err(info->dev, "Got non cmd complete fw event\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+       if (ev->status != 0) {
+               dev_err(info->dev, "Got error status from fw command\n");
+               err = -EPROTO;
+               goto ret;
+       }
+
+ret:
+       info->fw_error = err;
+       complete(&info->fw_completion);
+}
+
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       struct sk_buff *skb;
+       int err = 0;
+
+       info->fw_error = 0;
+
+       while ((skb = skb_dequeue(fw_queue)) != NULL) {
+               /* We should allways send word aligned data to h4+ devices */
+               if (skb->len % 2) {
+                       err = skb_pad(skb, 1);
+               }
+               if (err)
+                       return err;
+
+               init_completion(&info->fw_completion);
+               skb_queue_tail(&info->txq, skb);
+               tasklet_schedule(&info->tx_task);
+
+               if (!wait_for_completion_timeout(&info->fw_completion, HZ)) {
+                       dev_err(info->dev, "Timeout while sending brf6150 fw\n");
+                       return -ETIMEDOUT;
+               }
+
+               if (info->fw_error) {
+                       dev_err(info->dev, "There was fw_error while sending bfr6150 fw\n");
+                       return -EPROTO;
+               }
+       }
+       NBT_DBG_FW("Firmware sent\n");
+
+       return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw.c b/drivers/bluetooth/hci_h4p/fw.c
new file mode 100644 (file)
index 0000000..792b6b7
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+                                const struct firmware **fw_entry)
+{
+       int err;
+
+       fw_pos = 0;
+       NBT_DBG_FW("Opening %d firmware\n", info->chip_type);
+       switch (info->chip_type) {
+       case BT_CHIP_TI:
+               err = request_firmware(fw_entry, "brf6150fw.bin", info->dev);
+               break;
+       case BT_CHIP_CSR:
+               err = request_firmware(fw_entry, "bc4fw.bin", info->dev);
+               break;
+       default:
+               dev_err(info->dev, "Invalid chip type\n");
+               *fw_entry = NULL;
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+       release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+                              const struct firmware *fw_entry, int how)
+{
+       unsigned int cmd_len;
+
+       if (fw_pos >= fw_entry->size) {
+               return 0;
+       }
+
+       cmd_len = fw_entry->data[fw_pos++];
+       if (!cmd_len)
+               return 0;
+
+       if (fw_pos + cmd_len > fw_entry->size) {
+               dev_err(info->dev, "Corrupted firmware image\n");
+               return -EMSGSIZE;
+       }
+
+       *skb = bt_skb_alloc(cmd_len, how);
+       if (!*skb) {
+               dev_err(info->dev, "Cannot reserve memory for buffer\n");
+               return -ENOMEM;
+       }
+       memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+       fw_pos += cmd_len;
+
+       return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       const struct firmware *fw_entry = NULL;
+       struct sk_buff *skb = NULL;
+       int err;
+
+       err = hci_h4p_open_firmware(info, &fw_entry);
+       if (err < 0 || !fw_entry)
+               goto err_clean;
+
+       while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+               if (err < 0 || !skb)
+                       goto err_clean;
+
+               skb_queue_tail(fw_queue, skb);
+       }
+
+err_clean:
+       hci_h4p_close_firmware(fw_entry);
+       return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+       int err;
+
+       switch(info->chip_type) {
+       case BT_CHIP_CSR:
+               err = hci_h4p_bc4_send_fw(info, fw_queue);
+               break;
+       case BT_CHIP_TI:
+               err = hci_h4p_brf6150_send_fw(info, fw_queue);
+               break;
+       default:
+               dev_err(info->dev, "Don't know how to send firmware\n");
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+       switch (info->chip_type) {
+       case BT_CHIP_CSR:
+               hci_h4p_bc4_parse_fw_event(info, skb);
+               break;
+       case BT_CHIP_TI:
+               hci_h4p_brf6150_parse_fw_event(info, skb);
+               break;
+       default:
+               dev_err(info->dev, "Don't know how to parse fw event\n");
+               info->fw_error = -EINVAL;
+       }
+
+       return;
+}
diff --git a/drivers/bluetooth/hci_h4p/hci_h4p.h b/drivers/bluetooth/hci_h4p/hci_h4p.h
new file mode 100644 (file)
index 0000000..85e9116
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <mach/board.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define UART_SYSC_OMAP_RESET   0x03
+#define UART_SYSS_RESETDONE    0x01
+#define UART_OMAP_SCR_EMPTY_THR        0x08
+#define UART_OMAP_SCR_WAKEUP   0x10
+#define UART_OMAP_SSR_WAKEUP   0x02
+#define UART_OMAP_SSR_TXFULL   0x01
+
+#if 0
+#define NBT_DBG(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG(...)
+#endif
+
+#if 0
+#define NBT_DBG_FW(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_FW(...)
+#endif
+
+#if 0
+#define NBT_DBG_POWER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_POWER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_TRANSFER(...)
+#endif
+
+#if 0
+#define NBT_DBG_TRANSFER_NF(fmt, arg...)  printk(fmt "" , ## arg)
+#else
+#define NBT_DBG_TRANSFER_NF(...)
+#endif
+
+#if 0
+#define NBT_DBG_DMA(fmt, arg...)  printk("%s: " fmt "" , __FUNCTION__ , ## arg)
+#else
+#define NBT_DBG_DMA(...)
+#endif
+
+struct hci_h4p_info {
+       struct hci_dev *hdev;
+       spinlock_t lock;
+
+       void __iomem *uart_base;
+       unsigned long uart_phys_base;
+       int irq;
+       struct device *dev;
+       u8 bdaddr[6];
+       u8 chip_type;
+       u8 bt_wakeup_gpio;
+       u8 host_wakeup_gpio;
+       u8 reset_gpio;
+       u8 bt_sysclk;
+
+
+       struct sk_buff_head fw_queue;
+       struct sk_buff *alive_cmd_skb;
+       struct completion init_completion;
+       struct completion fw_completion;
+       int fw_error;
+       int init_error;
+
+       struct sk_buff_head txq;
+       struct tasklet_struct tx_task;
+
+       struct sk_buff *rx_skb;
+       long rx_count;
+       unsigned long rx_state;
+       unsigned long garbage_bytes;
+       struct tasklet_struct rx_task;
+
+       int pm_enabled;
+       int tx_pm_enabled;
+       int rx_pm_enabled;
+       struct timer_list tx_pm_timer;
+       struct timer_list rx_pm_timer;
+
+       int tx_clocks_en;
+       int rx_clocks_en;
+       spinlock_t clocks_lock;
+       struct clk *uart_iclk;
+       struct clk *uart_fclk;
+};
+
+#define MAX_BAUD_RATE          921600
+#define BC4_MAX_BAUD_RATE      3692300
+#define UART_CLOCK             48000000
+#define BT_INIT_DIVIDER                320
+#define BT_BAUDRATE_DIVIDER    384000000
+#define BT_SYSCLK_DIV          1000
+#define INIT_SPEED             120000
+
+#define H4_TYPE_SIZE           1
+
+/* H4+ packet types */
+#define H4_CMD_PKT             0x01
+#define H4_ACL_PKT             0x02
+#define H4_SCO_PKT             0x03
+#define H4_EVT_PKT             0x04
+#define H4_NEG_PKT             0x06
+#define H4_ALIVE_PKT           0x07
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE      1
+#define WAIT_FOR_HEADER                2
+#define WAIT_FOR_DATA          3
+
+struct hci_fw_event {
+       struct hci_event_hdr hev;
+       struct hci_ev_cmd_complete cmd;
+       u8 status;
+} __attribute__ ((packed));
+
+struct hci_bc4_set_bdaddr {
+       u8 type;
+       struct hci_command_hdr cmd_hdr;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+                               struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+                       struct sk_buff_head *fw_queue);
+
+void hci_h4p_brf6150_parse_fw_event(struct hci_h4p_info *info,
+                                   struct sk_buff *skb);
+int hci_h4p_brf6150_send_fw(struct hci_h4p_info *info,
+                           struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+int hci_h4p_sysfs_create_files(struct device *dev);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+int hci_h4p_init_uart(struct hci_h4p_info *info);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/hci_h4p/sysfs.c b/drivers/bluetooth/hci_h4p/sysfs.c
new file mode 100644 (file)
index 0000000..687df69
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "hci_h4p.h"
+
+#ifdef CONFIG_SYSFS
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev, struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+       unsigned int bdaddr[6];
+       int ret, i;
+
+       ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+                       &bdaddr[0], &bdaddr[1], &bdaddr[2],
+                       &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+       if (ret != 6) {
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 6; i++)
+               info->bdaddr[i] = bdaddr[i] & 0xff;
+
+       return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev, struct device_attribute *attr,
+                                  char *buf)
+{
+       struct hci_h4p_info *info = (struct hci_h4p_info*)dev_get_drvdata(dev);
+
+       return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+                      info->bdaddr[0],
+                      info->bdaddr[1],
+                      info->bdaddr[2],
+                      info->bdaddr[3],
+                      info->bdaddr[4],
+                      info->bdaddr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr, hci_h4p_store_bdaddr);
+int hci_h4p_sysfs_create_files(struct device *dev)
+{
+       return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+#endif
diff --git a/drivers/bluetooth/hci_h4p/uart.c b/drivers/bluetooth/hci_h4p/uart.c
new file mode 100644 (file)
index 0000000..1b75a42
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+       outb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+       return inb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+       u8 b;
+
+       b = hci_h4p_inb(info, UART_MCR);
+       if (active)
+               b |= UART_MCR_RTS;
+       else
+               b &= ~UART_MCR_RTS;
+       hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+                        int timeout_ms)
+{
+       int okay;
+       unsigned long timeout;
+
+       okay = 0;
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       for (;;) {
+               int state;
+
+               state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+               if (active) {
+                       if (state)
+                               return 0;
+               } else {
+                       if (!state)
+                               return 0;
+               }
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+       u8 lcr, b;
+
+       lcr = hci_h4p_inb(info, UART_LCR);
+       hci_h4p_outb(info, UART_LCR, 0xbf);
+       b = hci_h4p_inb(info, UART_EFR);
+       if (on)
+               b |= which;
+       else
+               b &= ~which;
+       hci_h4p_outb(info, UART_EFR, b);
+       hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&info->lock, flags);
+       __hci_h4p_set_auto_ctsrts(info, on, which);
+       spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+       unsigned int divisor;
+       u8 lcr, mdr1;
+
+       NBT_DBG("Setting speed %lu\n", speed);
+
+       if (speed >= 460800) {
+               divisor = UART_CLOCK / 13 / speed;
+               mdr1 = 3;
+       } else {
+               divisor = UART_CLOCK / 16 / speed;
+               mdr1 = 0;
+       }
+
+       hci_h4p_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
+       lcr = hci_h4p_inb(info, UART_LCR);
+       hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
+       hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
+       hci_h4p_outb(info, UART_DLM, divisor >> 8);
+       hci_h4p_outb(info, UART_LCR, lcr);
+       hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+       int count = 0;
+
+       /* Reset the  UART */
+       hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+       while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+               if (count++ > 100) {
+                       dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+                       return -ENODEV;
+               }
+               udelay(1);
+       }
+
+       return 0;
+}
+
+int hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+       int err;
+
+       err = hci_h4p_reset_uart(info);
+       if (err < 0)
+               return err;
+
+       /* Enable and setup FIFO */
+       hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+       hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
+       hci_h4p_outb(info, UART_OMAP_SCR, 0x80);
+       hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+       hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+       hci_h4p_outb(info, UART_TI752_TLR, 0x1f);
+       hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+       hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+                    UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_00);
+       hci_h4p_outb(info, UART_IER, UART_IER_RDI);
+
+       return 0;
+}
diff --git a/drivers/cbus/Kconfig b/drivers/cbus/Kconfig
new file mode 100644 (file)
index 0000000..25f8039
--- /dev/null
@@ -0,0 +1,89 @@
+#
+# CBUS device configuration
+#
+
+menu "CBUS support"
+
+config CBUS
+       depends on ARCH_OMAP
+       bool "CBUS support on OMAP"
+       ---help---
+         CBUS is a proprietary serial protocol by Nokia.  It is mainly
+         used for accessing Energy Management auxiliary chips.
+
+         If you want CBUS support, you should say Y here.
+
+config CBUS_TAHVO
+       depends on CBUS
+       bool "Support for Tahvo"
+       ---help---
+         Tahvo is a mixed signal ASIC with some system features
+
+         If you want Tahvo support, you should say Y here.
+
+config CBUS_TAHVO_USER
+       depends on CBUS_TAHVO
+       bool "Support for Tahvo user space functions"
+       ---help---
+         If you want support for Tahvo's user space read/write etc. functions,
+         you should say Y here.
+
+config CBUS_TAHVO_USB
+       depends on CBUS_TAHVO && USB
+       tristate "Support for Tahvo USB transceiver"
+       ---help---
+         If you want Tahvo support for USB transceiver, say Y or M here.
+
+config CBUS_TAHVO_USB_HOST_BY_DEFAULT
+       depends on CBUS_TAHVO_USB && USB_OTG
+       boolean "Device in USB host mode by default"
+       ---help---
+         Say Y here, if you want the device to enter USB host mode
+         by default on bootup.
+
+config CBUS_RETU
+       depends on CBUS
+       bool "Support for Retu"
+       ---help---
+         Retu is a mixed signal ASIC with some system features
+
+         If you want Retu support, you should say Y here.
+
+config CBUS_RETU_USER
+       depends on CBUS_RETU
+       bool "Support for Retu user space functions"
+       ---help---
+         If you want support for Retu's user space read/write etc. functions,
+         you should say Y here.
+
+config CBUS_RETU_POWERBUTTON
+       depends on CBUS_RETU
+       bool "Support for Retu power button"
+       ---help---
+         The power button on Nokia 770 is connected to the Retu ASIC.
+
+         If you want support for the Retu power button, you should say Y here.
+
+config CBUS_RETU_RTC
+       depends on CBUS_RETU && SYSFS
+       tristate "Support for Retu pseudo-RTC"
+       ---help---
+         Say Y here if you want support for the device that alleges to be an
+         RTC in Retu. This will expose a sysfs interface for it.
+
+config CBUS_RETU_WDT
+       depends on CBUS_RETU && SYSFS
+       tristate "Support for Retu watchdog timer"
+       ---help---
+         Say Y here if you want support for the watchdog in Retu. This will
+         expose a sysfs interface to grok it.
+
+config CBUS_RETU_HEADSET
+       depends on CBUS_RETU && SYSFS
+       tristate "Support for headset detection with Retu/Vilma"
+       ---help---
+         Say Y here if you want support detecting a headset that's connected
+         to Retu/Vilma. Detection state and events are exposed through
+         sysfs.
+
+endmenu
diff --git a/drivers/cbus/Makefile b/drivers/cbus/Makefile
new file mode 100644 (file)
index 0000000..347c2a4
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for CBUS.
+#
+
+obj-$(CONFIG_CBUS)             += cbus.o
+obj-$(CONFIG_CBUS_TAHVO)       += tahvo.o
+obj-$(CONFIG_CBUS_RETU)                += retu.o
+obj-$(CONFIG_CBUS_TAHVO_USB)   += tahvo-usb.o
+obj-$(CONFIG_CBUS_RETU_POWERBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_CBUS_RETU_RTC)    += retu-rtc.o
+obj-$(CONFIG_CBUS_RETU_WDT)    += retu-wdt.o
+obj-$(CONFIG_CBUS_TAHVO_USER)  += tahvo-user.o
+obj-$(CONFIG_CBUS_RETU_USER)   += retu-user.o
+obj-$(CONFIG_CBUS_RETU_HEADSET)        += retu-headset.o
diff --git a/drivers/cbus/cbus.c b/drivers/cbus/cbus.c
new file mode 100644 (file)
index 0000000..d72c49a
--- /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 <mach/gpio.h>
+#include <mach/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 = OMAP1_IO_ADDRESS(OMAP_MPUIO_BASE);
+#else
+       base = 0;
+#endif
+
+       if (data < 0)
+               is_read = 1;
+
+       /* We don't want interrupts disturbing our transfer */
+       spin_lock_irqsave(&host->lock, flags);
+
+       /* Reset state and start of transfer, SEL stays down during transfer */
+       cbus_set_gpio_dataout(base, host->sel_gpio, 0);
+
+       /* Set the DAT pin to output */
+       cbus_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-headset.c b/drivers/cbus/retu-headset.c
new file mode 100644 (file)
index 0000000..e798bc2
--- /dev/null
@@ -0,0 +1,355 @@
+/**
+ * Retu/Vilma headset detection
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * Written by Juha Yrjölä
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+
+#include "retu.h"
+
+#define RETU_ADC_CHANNEL_HOOKDET       0x05
+
+#define RETU_HEADSET_KEY               KEY_PHONE
+
+struct retu_headset {
+       spinlock_t                      lock;
+       struct mutex                    mutex;
+       struct platform_device          *pdev;
+       struct input_dev                *idev;
+       unsigned                        bias_enabled;
+       unsigned                        detection_enabled;
+       unsigned                        pressed;
+       struct timer_list               enable_timer;
+       struct timer_list               detect_timer;
+};
+
+static void retu_headset_set_bias(int enable)
+{
+       if (enable) {
+               retu_set_clear_reg_bits(RETU_REG_AUDTXR,
+                                       (1 << 0) | (1 << 1), 0);
+               msleep(2);
+               retu_set_clear_reg_bits(RETU_REG_AUDTXR, 1 << 3, 0);
+       } else {
+               retu_set_clear_reg_bits(RETU_REG_AUDTXR, 0,
+                                       (1 << 0) | (1 << 1) | (1 << 3));
+       }
+}
+
+static void retu_headset_enable(struct retu_headset *hs)
+{
+       mutex_lock(&hs->mutex);
+       if (!hs->bias_enabled) {
+               hs->bias_enabled = 1;
+               retu_headset_set_bias(1);
+       }
+       mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_disable(struct retu_headset *hs)
+{
+       mutex_lock(&hs->mutex);
+       if (hs->bias_enabled) {
+               hs->bias_enabled = 0;
+               retu_headset_set_bias(0);
+       }
+       mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_det_enable(struct retu_headset *hs)
+{
+       mutex_lock(&hs->mutex);
+       if (!hs->detection_enabled) {
+               hs->detection_enabled = 1;
+               retu_set_clear_reg_bits(RETU_REG_CC1, (1 << 10) | (1 << 8), 0);
+               retu_enable_irq(RETU_INT_HOOK);
+       }
+       mutex_unlock(&hs->mutex);
+}
+
+static void retu_headset_det_disable(struct retu_headset *hs)
+{
+       unsigned long flags;
+
+       mutex_lock(&hs->mutex);
+       if (hs->detection_enabled) {
+               hs->detection_enabled = 0;
+               retu_disable_irq(RETU_INT_HOOK);
+               del_timer_sync(&hs->enable_timer);
+               del_timer_sync(&hs->detect_timer);
+               spin_lock_irqsave(&hs->lock, flags);
+               if (hs->pressed)
+                       input_report_key(hs->idev, RETU_HEADSET_KEY, 0);
+               spin_unlock_irqrestore(&hs->lock, flags);
+               retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8));
+       }
+       mutex_unlock(&hs->mutex);
+}
+
+static ssize_t retu_headset_hookdet_show(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
+{
+       int val;
+
+       val = retu_read_adc(RETU_ADC_CHANNEL_HOOKDET);
+       return sprintf(buf, "%d\n", val);
+}
+
+static DEVICE_ATTR(hookdet, S_IRUGO, retu_headset_hookdet_show, NULL);
+
+static ssize_t retu_headset_enable_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct retu_headset *hs = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", hs->bias_enabled);
+}
+
+static ssize_t retu_headset_enable_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct retu_headset *hs = dev_get_drvdata(dev);
+       int enable;
+
+       if (sscanf(buf, "%u", &enable) != 1)
+               return -EINVAL;
+       if (enable)
+               retu_headset_enable(hs);
+       else
+               retu_headset_disable(hs);
+       return count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP,
+                  retu_headset_enable_show, retu_headset_enable_store);
+
+static ssize_t retu_headset_enable_det_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       struct retu_headset *hs = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", hs->detection_enabled);
+}
+
+static ssize_t retu_headset_enable_det_store(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t count)
+{
+       struct retu_headset *hs = dev_get_drvdata(dev);
+       int enable;
+
+       if (sscanf(buf, "%u", &enable) != 1)
+               return -EINVAL;
+       if (enable)
+               retu_headset_det_enable(hs);
+       else
+               retu_headset_det_disable(hs);
+       return count;
+}
+
+static DEVICE_ATTR(enable_det, S_IRUGO | S_IWUSR | S_IWGRP,
+                  retu_headset_enable_det_show,
+                  retu_headset_enable_det_store);
+
+static void retu_headset_hook_interrupt(unsigned long arg)
+{
+       struct retu_headset *hs = (struct retu_headset *) arg;
+       unsigned long flags;
+
+       retu_ack_irq(RETU_INT_HOOK);
+       spin_lock_irqsave(&hs->lock, flags);
+       if (!hs->pressed) {
+               /* Headset button was just pressed down. */
+               hs->pressed = 1;
+               input_report_key(hs->idev, RETU_HEADSET_KEY, 1);
+       }
+       spin_unlock_irqrestore(&hs->lock, flags);
+       retu_set_clear_reg_bits(RETU_REG_CC1, 0, (1 << 10) | (1 << 8));
+       mod_timer(&hs->enable_timer, jiffies + msecs_to_jiffies(50));
+}
+
+static void retu_headset_enable_timer(unsigned long arg)
+{
+       struct retu_headset *hs = (struct retu_headset *) arg;
+
+       retu_set_clear_reg_bits(RETU_REG_CC1, (1 << 10) | (1 << 8), 0);
+       mod_timer(&hs->detect_timer, jiffies + msecs_to_jiffies(350));
+}
+
+static void retu_headset_detect_timer(unsigned long arg)
+{
+       struct retu_headset *hs = (struct retu_headset *) arg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hs->lock, flags);
+       if (hs->pressed) {
+               hs->pressed = 0;
+               input_report_key(hs->idev, RETU_HEADSET_KEY, 0);
+       }
+       spin_unlock_irqrestore(&hs->lock, flags);
+}
+
+static int __init retu_headset_probe(struct platform_device *pdev)
+{
+       struct retu_headset *hs;
+       int r;
+
+       hs = kzalloc(sizeof(*hs), GFP_KERNEL);
+       if (hs == NULL)
+               return -ENOMEM;
+
+       hs->pdev = pdev;
+
+       hs->idev = input_allocate_device();
+       if (hs->idev == NULL) {
+               r = -ENOMEM;
+               goto err1;
+       }
+       hs->idev->name = "retu-headset";
+       hs->idev->dev.parent = &pdev->dev;
+       set_bit(EV_KEY, hs->idev->evbit);
+       set_bit(RETU_HEADSET_KEY, hs->idev->keybit);
+       r = input_register_device(hs->idev);
+       if (r < 0)
+               goto err2;
+
+       r = device_create_file(&pdev->dev, &dev_attr_hookdet);
+       if (r < 0)
+               goto err3;
+       r = device_create_file(&pdev->dev, &dev_attr_enable);
+       if (r < 0)
+               goto err4;
+       r = device_create_file(&pdev->dev, &dev_attr_enable_det);
+       if (r < 0)
+               goto err5;
+       platform_set_drvdata(pdev, hs);
+
+       spin_lock_init(&hs->lock);
+       mutex_init(&hs->mutex);
+       setup_timer(&hs->enable_timer, retu_headset_enable_timer,
+                   (unsigned long) hs);
+       setup_timer(&hs->detect_timer, retu_headset_detect_timer,
+                   (unsigned long) hs);
+
+       r = retu_request_irq(RETU_INT_HOOK, retu_headset_hook_interrupt,
+                            (unsigned long) hs, "hookdet");
+       if (r != 0) {
+               dev_err(&pdev->dev, "hookdet IRQ not available\n");
+               goto err6;
+       }
+       retu_disable_irq(RETU_INT_HOOK);
+       return 0;
+err6:
+       device_remove_file(&pdev->dev, &dev_attr_enable_det);
+err5:
+       device_remove_file(&pdev->dev, &dev_attr_enable);
+err4:
+       device_remove_file(&pdev->dev, &dev_attr_hookdet);
+err3:
+       input_unregister_device(hs->idev);
+err2:
+       input_free_device(hs->idev);
+err1:
+       kfree(hs);
+       return r;
+}
+
+static int retu_headset_remove(struct platform_device *pdev)
+{
+       struct retu_headset *hs = platform_get_drvdata(pdev);
+
+       device_remove_file(&pdev->dev, &dev_attr_hookdet);
+       device_remove_file(&pdev->dev, &dev_attr_enable);
+       device_remove_file(&pdev->dev, &dev_attr_enable_det);
+       retu_headset_disable(hs);
+       retu_headset_det_disable(hs);
+       retu_free_irq(RETU_INT_HOOK);
+       input_unregister_device(hs->idev);
+       input_free_device(hs->idev);
+       return 0;
+}
+
+static int retu_headset_suspend(struct platform_device *pdev,
+                               pm_message_t mesg)
+{
+       struct retu_headset *hs = platform_get_drvdata(pdev);
+
+       mutex_lock(&hs->mutex);
+       if (hs->bias_enabled)
+               retu_headset_set_bias(0);
+       mutex_unlock(&hs->mutex);
+
+       return 0;
+}
+
+static int retu_headset_resume(struct platform_device *pdev)
+{
+       struct retu_headset *hs = platform_get_drvdata(pdev);
+
+       mutex_lock(&hs->mutex);
+       if (hs->bias_enabled)
+               retu_headset_set_bias(1);
+       mutex_unlock(&hs->mutex);
+
+       return 0;
+}
+
+static struct platform_driver retu_headset_driver = {
+       .probe          = retu_headset_probe,
+       .remove         = retu_headset_remove,
+       .suspend        = retu_headset_suspend,
+       .resume         = retu_headset_resume,
+       .driver         = {
+               .name   = "retu-headset",
+       },
+};
+
+static int __init retu_headset_init(void)
+{
+       int r;
+
+       printk(KERN_INFO "Retu/Vilma headset driver initializing\n");
+
+       r = platform_driver_register(&retu_headset_driver);
+       if (r < 0)
+               return r;
+
+       return 0;
+}
+
+static void __exit retu_headset_exit(void)
+{
+       platform_driver_unregister(&retu_headset_driver);
+}
+
+module_init(retu_headset_init);
+module_exit(retu_headset_exit);
+
+MODULE_DESCRIPTION("Retu/Vilma headset detection");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä");
diff --git a/drivers/cbus/retu-pwrbutton.c b/drivers/cbus/retu-pwrbutton.c
new file mode 100644 (file)
index 0000000..38d7aa4
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * drivers/cbus/retu-pwrbutton.c
+ *
+ * Driver for sending retu power button event to input-layer
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Written by Ari Saastamoinen <ari.saastamoinen@elektrobit.com>
+ *
+ * Contact Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+
+#include "retu.h"
+
+#define RETU_STATUS_PWRONX     (1 << 5)
+
+#define PWRBTN_DELAY           20
+#define PWRBTN_UP              0
+#define PWRBTN_PRESSED         1
+
+static int pwrbtn_state;
+static struct input_dev *pwrbtn_dev;
+static struct timer_list pwrbtn_timer;
+
+static void retubutton_timer_func(unsigned long arg)
+{
+       int state;
+
+       if (retu_read_reg(RETU_REG_STATUS) & RETU_STATUS_PWRONX)
+               state = PWRBTN_UP;
+       else
+               state = PWRBTN_PRESSED;
+
+       if (pwrbtn_state != state) {
+               input_report_key(pwrbtn_dev, KEY_POWER, state);
+               pwrbtn_state = state;
+       }
+}
+
+/**
+ * Interrupt function is called whenever power button key is pressed
+ * or released.
+ */
+static void retubutton_irq(unsigned long arg)
+{
+       retu_ack_irq(RETU_INT_PWR);
+       mod_timer(&pwrbtn_timer, jiffies + msecs_to_jiffies(PWRBTN_DELAY));
+}
+
+/**
+ * Init function.
+ * Allocates interrupt for power button and registers itself to input layer.
+ */
+static int __init retubutton_init(void)
+{
+       int irq;
+
+       printk(KERN_INFO "Retu power button driver initialized\n");
+       irq = RETU_INT_PWR;
+
+       init_timer(&pwrbtn_timer);
+       pwrbtn_timer.function = retubutton_timer_func;
+
+       if (retu_request_irq(irq, &retubutton_irq, 0, "PwrOnX") < 0) {
+               printk(KERN_ERR "%s@%s: Cannot allocate irq\n",
+                      __FUNCTION__, __FILE__);
+               return -EBUSY;
+       }
+
+       pwrbtn_dev = input_allocate_device();
+       if (!pwrbtn_dev)
+               return -ENOMEM;
+
+       pwrbtn_dev->evbit[0] = BIT_MASK(EV_KEY);
+       pwrbtn_dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+       pwrbtn_dev->name = "retu-pwrbutton";
+
+       return input_register_device(pwrbtn_dev);
+}
+
+/**
+ * Cleanup function which is called when driver is unloaded
+ */
+static void __exit retubutton_exit(void)
+{
+       retu_free_irq(RETU_INT_PWR);
+       del_timer_sync(&pwrbtn_timer);
+       input_unregister_device(pwrbtn_dev);
+}
+
+module_init(retubutton_init);
+module_exit(retubutton_exit);
+
+MODULE_DESCRIPTION("Retu Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ari Saastamoinen");
diff --git a/drivers/cbus/retu-rtc.c b/drivers/cbus/retu-rtc.c
new file mode 100644 (file)
index 0000000..1ebc33b
--- /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 platform_device retu_rtc_device;
+
+static void retu_rtca_disable(void)
+{
+       retu_disable_irq(RETU_INT_RTCA);
+       retu_rtc_alarm_expired = 1;
+       retu_rtc_barrier();
+       retu_write_reg(RETU_REG_RTCHMAR, (24 << 8) | 60);
+}
+
+static void retu_rtca_expired(struct work_struct *unused)
+{
+       retu_rtca_disable();
+       sysfs_notify(&retu_rtc_device.dev.kobj, NULL, "alarm_expired");
+}
+
+DECLARE_WORK(retu_rtca_work, retu_rtca_expired);
+
+/*
+ * RTCHMR RTCHMAR RTCCAL must be accessed within 0.9 s since the seconds
+ * interrupt has been signaled in the IDR register
+ */
+static void retu_rtcs_interrupt(unsigned long unused)
+{
+       retu_ack_irq(RETU_INT_RTCS);
+       complete_all(&retu_rtc_sync);
+}
+
+static void retu_rtca_interrupt(unsigned long unused)
+{
+       retu_ack_irq(RETU_INT_RTCA);
+       schedule_work(&retu_rtca_work);
+}
+
+static int retu_rtc_init_irq(void)
+{
+       int ret;
+
+       ret = retu_request_irq(RETU_INT_RTCS, retu_rtcs_interrupt, 0, "RTCS");
+       if (ret != 0)
+               return ret;
+       /*
+        * We will take care of enabling and disabling the interrupt
+        * elsewhere, so leave it off by default..
+        */
+       retu_disable_irq(RETU_INT_RTCS);
+
+       ret = retu_request_irq(RETU_INT_RTCA, retu_rtca_interrupt, 0, "RTCA");
+       if (ret != 0) {
+               retu_free_irq(RETU_INT_RTCS);
+               return ret;
+       }
+       retu_disable_irq(RETU_INT_RTCA);
+
+       return 0;
+}
+
+
+static int __devinit retu_rtc_probe(struct device *dev)
+{
+       int r;
+
+       retu_rtc_alarm_expired = retu_read_reg(RETU_REG_IDR) &
+                                              (0x1 << RETU_INT_RTCA);
+
+       if ((r = retu_rtc_init_irq()) != 0)
+               return r;
+
+       mutex_init(&retu_rtc_mutex);
+
+       /* If the calibration register is zero, we've probably lost
+        * power */
+       if (retu_read_reg(RETU_REG_RTCCALR) & 0x00ff)
+               retu_rtc_reset_occurred = 0;
+       else
+               retu_rtc_do_reset();
+
+       if ((r = device_create_file(dev, &dev_attr_time)) != 0)
+               return r;
+       else if ((r = device_create_file(dev, &dev_attr_reset)) != 0)
+               goto err_unregister_time;
+       else if ((r = device_create_file(dev, &dev_attr_alarm)) != 0)
+               goto err_unregister_reset;
+       else if ((r = device_create_file(dev, &dev_attr_alarm_expired)) != 0)
+               goto err_unregister_alarm;
+       else if ((r = device_create_file(dev, &dev_attr_cal)) != 0)
+               goto err_unregister_alarm_expired;
+       else
+               return r;
+
+err_unregister_alarm_expired:
+       device_remove_file(dev, &dev_attr_alarm_expired);
+err_unregister_alarm:
+       device_remove_file(dev, &dev_attr_alarm);
+err_unregister_reset:
+       device_remove_file(dev, &dev_attr_reset);
+err_unregister_time:
+       device_remove_file(dev, &dev_attr_time);
+       return r;
+}
+
+static int __devexit retu_rtc_remove(struct device *dev)
+{
+       retu_disable_irq(RETU_INT_RTCS);
+       retu_free_irq(RETU_INT_RTCS);
+       retu_free_irq(RETU_INT_RTCA);
+       device_remove_file(dev, &dev_attr_cal);
+       device_remove_file(dev, &dev_attr_alarm_expired);
+       device_remove_file(dev, &dev_attr_alarm);
+       device_remove_file(dev, &dev_attr_reset);
+       device_remove_file(dev, &dev_attr_time);
+       return 0;
+}
+
+static struct device_driver retu_rtc_driver = {
+       .name           = "retu-rtc",
+       .bus            = &platform_bus_type,
+       .probe          = retu_rtc_probe,
+       .remove         = __devexit_p(retu_rtc_remove),
+};
+
+static struct platform_device retu_rtc_device = {
+       .name           = "retu-rtc",
+       .id             = -1,
+       .dev            = {
+               .release        = retu_rtc_device_release,
+       },
+};
+
+/* This function provides syncronization with the RTCS interrupt handler */
+static void retu_rtc_barrier(void)
+{
+       INIT_COMPLETION(retu_rtc_sync);
+       retu_ack_irq(RETU_INT_RTCS);
+       retu_enable_irq(RETU_INT_RTCS);
+       wait_for_completion(&retu_rtc_sync);
+       retu_disable_irq(RETU_INT_RTCS);
+}
+
+static int __init retu_rtc_init(void)
+{
+       int ret;
+
+       init_completion(&retu_rtc_exited);
+
+       if ((ret = driver_register(&retu_rtc_driver)) != 0)
+               return ret;
+
+       if ((ret = platform_device_register(&retu_rtc_device)) != 0)
+               goto err_unregister_driver;
+
+       return 0;
+
+err_unregister_driver:
+       driver_unregister(&retu_rtc_driver);
+       return ret;
+}
+
+static void __exit retu_rtc_exit(void)
+{
+       platform_device_unregister(&retu_rtc_device);
+       driver_unregister(&retu_rtc_driver);
+
+       wait_for_completion(&retu_rtc_exited);
+}
+
+module_init(retu_rtc_init);
+module_exit(retu_rtc_exit);
+
+MODULE_DESCRIPTION("Retu RTC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Mundt and Igor Stoppa");
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..b7b20b7
--- /dev/null
@@ -0,0 +1,202 @@
+/**
+ * drivers/cbus/retu-wdt.c
+ *
+ * Driver for Retu watchdog
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Amit Kucheria <amit.kucheria@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <linux/completion.h>
+#include <linux/errno.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include "cbus.h"
+#include "retu.h"
+
+/* Watchdog timeout in seconds */
+#define RETU_WDT_MIN_TIMER 0
+#define RETU_WDT_DEFAULT_TIMER 32
+#define RETU_WDT_MAX_TIMER 63
+
+static struct completion retu_wdt_completion;
+static DEFINE_MUTEX(retu_wdt_mutex);
+
+/* Current period of watchdog */
+static unsigned int period_val = RETU_WDT_DEFAULT_TIMER;
+static int counter_param = RETU_WDT_MAX_TIMER;
+
+static int retu_modify_counter(unsigned int new)
+{
+       int ret = 0;
+
+       if (new < RETU_WDT_MIN_TIMER || new > RETU_WDT_MAX_TIMER)
+               return -EINVAL;
+
+       mutex_lock(&retu_wdt_mutex);
+
+       period_val = new;
+       retu_write_reg(RETU_REG_WATCHDOG, (u16)period_val);
+
+       mutex_unlock(&retu_wdt_mutex);
+       return ret;
+}
+
+static ssize_t retu_wdt_period_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       /* Show current max counter */
+       return sprintf(buf, "%u\n", (u16)period_val);
+}
+
+static ssize_t retu_wdt_period_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       unsigned int new_period;
+       int ret;
+
+       if (sscanf(buf, "%u", &new_period) != 1) {
+               printk(KERN_ALERT "retu_wdt_period_store: Invalid input\n");
+               return -EINVAL;
+       }
+
+       ret = retu_modify_counter(new_period);
+       if (ret < 0)
+               return ret;
+
+       return strnlen(buf, count);
+}
+
+static ssize_t retu_wdt_counter_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u16 counter;
+
+       /* Show current value in watchdog counter */
+       counter = retu_read_reg(RETU_REG_WATCHDOG);
+
+       /* Only the 5 LSB are important */
+       return snprintf(buf, PAGE_SIZE, "%u\n", (counter & 0x3F));
+}
+
+static DEVICE_ATTR(period, S_IRUGO | S_IWUSR, retu_wdt_period_show, \
+                       retu_wdt_period_store);
+static DEVICE_ATTR(counter, S_IRUGO, retu_wdt_counter_show, NULL);
+
+static int __devinit retu_wdt_probe(struct device *dev)
+{
+       int ret;
+
+       ret = device_create_file(dev, &dev_attr_period);
+       if (ret) {
+               printk(KERN_ERR "retu_wdt_probe: Error creating "
+                                       "sys device file: period\n");
+               return ret;
+       }
+
+       ret = device_create_file(dev, &dev_attr_counter);
+       if (ret) {
+               device_remove_file(dev, &dev_attr_period);
+               printk(KERN_ERR "retu_wdt_probe: Error creating "
+                                       "sys device file: counter\n");
+       }
+
+       return ret;
+}
+
+static int __devexit retu_wdt_remove(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_period);
+       device_remove_file(dev, &dev_attr_counter);
+       return 0;
+}
+
+static void retu_wdt_device_release(struct device *dev)
+{
+       complete(&retu_wdt_completion);
+}
+
+static struct platform_device retu_wdt_device = {
+       .name = "retu-watchdog",
+       .id = -1,
+       .dev = {
+               .release = retu_wdt_device_release,
+       },
+};
+
+static struct device_driver retu_wdt_driver = {
+       .name = "retu-watchdog",
+       .bus = &platform_bus_type,
+       .probe = retu_wdt_probe,
+       .remove = __devexit_p(retu_wdt_remove),
+};
+
+static int __init retu_wdt_init(void)
+{
+       int ret;
+
+       init_completion(&retu_wdt_completion);
+
+       ret = driver_register(&retu_wdt_driver);
+       if (ret)
+               return ret;
+
+       ret = platform_device_register(&retu_wdt_device);
+       if (ret)
+               goto exit1;
+
+       /* passed as module parameter? */
+       ret = retu_modify_counter(counter_param);
+       if (ret == -EINVAL) {
+               ret = retu_modify_counter(RETU_WDT_DEFAULT_TIMER);
+               printk(KERN_INFO
+                      "retu_wdt_init: Intializing to default value\n");
+       }
+
+       printk(KERN_INFO "Retu watchdog driver initialized\n");
+       return ret;
+
+exit1:
+       driver_unregister(&retu_wdt_driver);
+       wait_for_completion(&retu_wdt_completion);
+
+       return ret;
+}
+
+static void __exit retu_wdt_exit(void)
+{
+       platform_device_unregister(&retu_wdt_device);
+       driver_unregister(&retu_wdt_driver);
+
+       wait_for_completion(&retu_wdt_completion);
+}
+
+module_init(retu_wdt_init);
+module_exit(retu_wdt_exit);
+module_param(counter_param, int, 0);
+
+MODULE_DESCRIPTION("Retu WatchDog");
+MODULE_AUTHOR("Amit Kucheria");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/cbus/retu.c b/drivers/cbus/retu.c
new file mode 100644 (file)
index 0000000..d94110b
--- /dev/null
@@ -0,0 +1,466 @@
+/**
+ * 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 <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/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);
+
+       if ((channel == 8) && retu_is_vilma) {
+               int scr = retu_read_reg(RETU_REG_ADCSCR);
+               int ch = (retu_read_reg(RETU_REG_ADCR) >> 10) & 0xf;
+               if (((scr & 0xff) != 0) && (ch != 8))
+                       retu_write_reg (RETU_REG_ADCSCR, (scr & ~0xff));
+       }
+
+       /* Select the channel and read result */
+       retu_write_reg(RETU_REG_ADCR, channel << 10);
+       res = retu_read_reg(RETU_REG_ADCR) & 0x3ff;
+
+       if (retu_is_vilma)
+               retu_write_reg(RETU_REG_ADCR, (1 << 13));
+
+       /* Unlock retu */
+       spin_unlock_irqrestore(&retu_lock, flags);
+
+       return res;
+}
+
+
+static u16 retu_disable_bogus_irqs(u16 mask)
+{
+       int i;
+
+       for (i = 0; i < MAX_RETU_IRQ_HANDLERS; i++) {
+               if (mask & (1 << i))
+                       continue;
+               if (retu_irq_handlers[i].func != NULL)
+                       continue;
+               /* an IRQ was enabled but we don't have a handler for it */
+               printk(KERN_INFO PFX "disabling bogus IRQ %d\n", i);
+               mask |= (1 << i);
+       }
+       return mask;
+}
+
+/*
+ * Disable given RETU interrupt
+ */
+void retu_disable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       spin_lock_irqsave(&retu_lock, flags);
+       mask = retu_read_reg(RETU_REG_IMR);
+       mask |= 1 << id;
+       mask = retu_disable_bogus_irqs(mask);
+       retu_write_reg(RETU_REG_IMR, mask);
+       spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Enable given RETU interrupt
+ */
+void retu_enable_irq(int id)
+{
+       unsigned long flags;
+       u16 mask;
+
+       if (id == 3) {
+               printk("Enabling Retu IRQ %d\n", id);
+               dump_stack();
+       }
+       spin_lock_irqsave(&retu_lock, flags);
+       mask = retu_read_reg(RETU_REG_IMR);
+       mask &= ~(1 << id);
+       mask = retu_disable_bogus_irqs(mask);
+       retu_write_reg(RETU_REG_IMR, mask);
+       spin_unlock_irqrestore(&retu_lock, flags);
+}
+
+/*
+ * Acknowledge given RETU interrupt
+ */
+void retu_ack_irq(int id)
+{
+       retu_write_reg(RETU_REG_IDR, 1 << id);
+}
+
+/*
+ * RETU interrupt handler. Only schedules the tasklet.
+ */
+static irqreturn_t retu_irq_handler(int irq, void *dev_id)
+{
+       tasklet_schedule(&retu_tasklet);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Tasklet handler
+ */
+static void retu_tasklet_handler(unsigned long data)
+{
+       struct retu_irq_handler_desc *hnd;
+       u16 id;
+       u16 im;
+       int i;
+
+       for (;;) {
+               id = retu_read_reg(RETU_REG_IDR);
+               im = ~retu_read_reg(RETU_REG_IMR);
+               id &= im;
+
+               if (!id)
+                       break;
+
+               for (i = 0; id != 0; i++, id >>= 1) {
+                       if (!(id & 1))
+                               continue;
+                       hnd = &retu_irq_handlers[i];
+                       if (hnd->func == NULL) {
+                               /* Spurious retu interrupt - disable and ack it */
+                               printk(KERN_INFO "Spurious Retu interrupt "
+                                                "(id %d)\n", i);
+                               retu_disable_irq(i);
+                               retu_ack_irq(i);
+                               continue;
+                       }
+                       hnd->func(hnd->arg);
+                       /*
+                        * Don't acknowledge the interrupt here
+                        * It must be done explicitly
+                        */
+               }
+       }
+}
+
+/*
+ * Register the handler for a given RETU interrupt source.
+ */
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name)
+{
+       struct retu_irq_handler_desc *hnd;
+
+       if (irq_handler == NULL || id >= MAX_RETU_IRQ_HANDLERS ||
+           name == NULL) {
+               printk(KERN_ERR PFX "Invalid arguments to %s\n",
+                      __FUNCTION__);
+               return -EINVAL;
+       }
+       hnd = &retu_irq_handlers[id];
+       if (hnd->func != NULL) {
+               printk(KERN_ERR PFX "IRQ %d already reserved\n", id);
+               return -EBUSY;
+       }
+       printk(KERN_INFO PFX "Registering interrupt %d for device %s\n",
+              id, name);
+       hnd->func = irq_handler;
+       hnd->arg = arg;
+       strlcpy(hnd->name, name, sizeof(hnd->name));
+
+       retu_ack_irq(id);
+       retu_enable_irq(id);
+
+       return 0;
+}
+
+/*
+ * Unregister the handler for a given RETU interrupt source.
+ */
+void retu_free_irq(int id)
+{
+       struct retu_irq_handler_desc *hnd;
+
+       if (id >= MAX_RETU_IRQ_HANDLERS) {
+               printk(KERN_ERR PFX "Invalid argument to %s\n",
+                      __FUNCTION__);
+               return;
+       }
+       hnd = &retu_irq_handlers[id];
+       if (hnd->func == NULL) {
+               printk(KERN_ERR PFX "IRQ %d already freed\n", id);
+               return;
+       }
+
+       retu_disable_irq(id);
+       hnd->func = NULL;
+}
+
+/**
+ * retu_power_off - Shut down power to system
+ *
+ * This function puts the system in power off state
+ */
+static void retu_power_off(void)
+{
+       /* Ignore power button state */
+       retu_write_reg(RETU_REG_CC1, retu_read_reg(RETU_REG_CC1) | 2);
+       /* Expire watchdog immediately */
+       retu_write_reg(RETU_REG_WATCHDOG, 0);
+       /* Wait for poweroff*/
+       for (;;);
+}
+
+/**
+ * retu_probe - Probe for Retu ASIC
+ * @dev: the Retu device
+ *
+ * Probe for the Retu ASIC and allocate memory
+ * for its device-struct if found
+ */
+static int __devinit retu_probe(struct device *dev)
+{
+       const struct omap_em_asic_bb5_config * em_asic_config;
+       int rev, ret;
+
+       /* Prepare tasklet */
+       tasklet_init(&retu_tasklet, retu_tasklet_handler, 0);
+
+       em_asic_config = omap_get_config(OMAP_TAG_EM_ASIC_BB5,
+                                        struct omap_em_asic_bb5_config);
+       if (em_asic_config == NULL) {
+               printk(KERN_ERR PFX "Unable to retrieve config data\n");
+               return -ENODATA;
+       }
+
+       retu_irq_pin = em_asic_config->retu_irq_gpio;
+
+       if ((ret = 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), IRQ_TYPE_EDGE_RISING);
+
+       retu_initialized = 1;
+
+       rev = retu_read_reg(RETU_REG_ASICR) & 0xff;
+       if (rev & (1 << 7))
+               retu_is_vilma = 1;
+
+       printk(KERN_INFO "%s v%d.%d found\n", retu_is_vilma ? "Vilma" : "Retu",
+              (rev >> 4) & 0x07, rev & 0x0f);
+
+       /* Mask all RETU interrupts */
+       retu_write_reg(RETU_REG_IMR, 0xffff);
+
+       ret = request_irq(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..c9e044c
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * drivers/cbus/retu.h
+ *
+ * Copyright (C) 2004, 2005 Nokia Corporation
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com> and
+ *           David Weinehall <david.weinehall@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DRIVERS_CBUS_RETU_H
+#define __DRIVERS_CBUS_RETU_H
+
+#include <linux/types.h>
+
+/* Registers */
+#define RETU_REG_ASICR         0x00    /* ASIC ID & revision */
+#define RETU_REG_IDR           0x01    /* Interrupt ID */
+#define RETU_REG_IMR           0x02    /* Interrupt mask */
+#define RETU_REG_RTCDSR                0x03    /* RTC seconds register */
+#define RETU_REG_RTCHMR                0x04    /* RTC hours and minutes register */
+#define RETU_REG_RTCHMAR       0x05    /* RTC hours and minutes alarm and time set register */
+#define RETU_REG_RTCCALR       0x06    /* RTC calibration register */
+#define RETU_REG_ADCR          0x08    /* ADC result */
+#define RETU_REG_ADCSCR                0x09    /* ADC sample ctrl */
+#define RETU_REG_CC1           0x0d    /* Common control register 1 */
+#define RETU_REG_CC2           0x0e    /* Common control register 2 */
+#define RETU_REG_CTRL_CLR      0x0f    /* Regulator clear register */
+#define RETU_REG_CTRL_SET      0x10    /* Regulator set register */
+#define RETU_REG_STATUS                0x16    /* Status register */
+#define RETU_REG_WATCHDOG      0x17    /* Watchdog register */
+#define RETU_REG_AUDTXR                0x18    /* Audio Codec Tx register */
+#define RETU_REG_MAX           0x1f
+
+/* Interrupt sources */
+#define RETU_INT_PWR           0
+#define RETU_INT_CHAR          1
+#define RETU_INT_RTCS          2
+#define RETU_INT_RTCM          3
+#define RETU_INT_RTCD          4
+#define RETU_INT_RTCA          5
+#define RETU_INT_HOOK          6
+#define RETU_INT_HEAD          7
+#define RETU_INT_ADCS          8
+
+#define        MAX_RETU_IRQ_HANDLERS   16
+
+int retu_read_reg(int reg);
+void retu_write_reg(int reg, u16 val);
+void retu_set_clear_reg_bits(int reg, u16 set, u16 clear);
+int retu_read_adc(int channel);
+int retu_request_irq(int id, void *irq_handler, unsigned long arg, char *name);
+void retu_free_irq(int id);
+void retu_enable_irq(int id);
+void retu_disable_irq(int id);
+void retu_ack_irq(int id);
+
+#ifdef CONFIG_CBUS_RETU_USER
+int retu_user_init(void);
+void retu_user_cleanup(void);
+#endif
+
+extern spinlock_t retu_lock;
+
+#endif /* __DRIVERS_CBUS_RETU_H */
diff --git a/drivers/cbus/tahvo-usb.c b/drivers/cbus/tahvo-usb.c
new file mode 100644 (file)
index 0000000..d8ad836
--- /dev/null
@@ -0,0 +1,777 @@
+/**
+ * drivers/cbus/tahvo-usb.c
+ *
+ * Tahvo USB transeiver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Parts copied from drivers/i2c/chips/isp1301_omap.c
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ *
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
+ *           Tony Lindgren <tony@atomide.com>, and
+ *           Timo Teräs <timo.teras@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <asm/irq.h>
+#include <mach/usb.h>
+
+#include "cbus.h"
+#include "tahvo.h"
+
+#define DRIVER_NAME     "tahvo-usb"
+
+#define USBR_SLAVE_CONTROL     (1 << 8)
+#define USBR_VPPVIO_SW         (1 << 7)
+#define USBR_SPEED             (1 << 6)
+#define USBR_REGOUT            (1 << 5)
+#define USBR_MASTER_SW2                (1 << 4)
+#define USBR_MASTER_SW1                (1 << 3)
+#define USBR_SLAVE_SW          (1 << 2)
+#define USBR_NSUSPEND          (1 << 1)
+#define USBR_SEMODE            (1 << 0)
+
+/* bits in OTG_CTRL */
+
+/* Bits that are controlled by OMAP OTG and are read-only */
+#define OTG_CTRL_OMAP_MASK     (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|\
+                               OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+/* Bits that are controlled by transceiver */
+#define OTG_CTRL_XCVR_MASK     (OTG_ASESSVLD|OTG_BSESSEND|\
+                               OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+/* Bits that are controlled by system */
+#define OTG_CTRL_SYS_MASK      (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|\
+                               OTG_B_HNPEN|OTG_BUSDROP)
+
+#if defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OTG)
+#error tahvo-otg.c does not work with OCHI yet!
+#endif
+
+#define TAHVO_MODE_HOST                0
+#define TAHVO_MODE_PERIPHERAL  1
+
+#ifdef CONFIG_USB_OTG
+#define TAHVO_MODE(tu)         (tu)->tahvo_mode
+#elif defined(CONFIG_USB_GADGET_OMAP)
+#define TAHVO_MODE(tu)         TAHVO_MODE_PERIPHERAL
+#else
+#define TAHVO_MODE(tu)         TAHVO_MODE_HOST
+#endif
+
+struct tahvo_usb {
+       struct platform_device *pt_dev;
+       struct otg_transceiver otg;
+       int vbus_state;
+       struct work_struct irq_work;
+       struct mutex serialize;
+#ifdef CONFIG_USB_OTG
+       int tahvo_mode;
+#endif
+};
+static struct platform_device tahvo_usb_device;
+
+/*
+ * ---------------------------------------------------------------------------
+ * OTG related functions
+ *
+ * These shoud be separated into omap-otg.c driver module, as they are used
+ * by various transceivers. These functions are needed in the UDC-only case
+ * as well. These functions are copied from GPL isp1301_omap.c
+ * ---------------------------------------------------------------------------
+ */
+static struct platform_device *tahvo_otg_dev;
+
+static irqreturn_t omap_otg_irq(int irq, void *arg)
+{
+       struct platform_device *otg_dev = (struct platform_device *) arg;
+       struct tahvo_usb *tu = (struct tahvo_usb *) otg_dev->dev.driver_data;
+       u16 otg_irq;
+
+       otg_irq = omap_readw(OTG_IRQ_SRC);
+       if (otg_irq & OPRT_CHG) {
+               omap_writew(OPRT_CHG, OTG_IRQ_SRC);
+       } else if (otg_irq & B_SRP_TMROUT) {
+               omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
+       } else if (otg_irq & B_HNP_FAIL) {
+               omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
+       } else if (otg_irq & A_SRP_DETECT) {
+               omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
+       } else if (otg_irq & A_REQ_TMROUT) {
+               omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
+       } else if (otg_irq & A_VBUS_ERR) {
+               omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
+       } else if (otg_irq & DRIVER_SWITCH) {
+               if ((!(omap_readl(OTG_CTRL) & OTG_DRIVER_SEL)) &&
+                  tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
+                       /* role is host */
+                       usb_bus_start_enum(tu->otg.host,
+                                          tu->otg.host->otg_port);
+               }
+               omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
+       } else
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+
+}
+
+static int omap_otg_init(void)
+{
+       u32 l;
+
+#ifdef CONFIG_USB_OTG
+       if (!tahvo_otg_dev) {
+               printk("tahvo-usb: no tahvo_otg_dev\n");
+               return -ENODEV;
+       }
+#endif
+
+       l = omap_readl(OTG_SYSCON_1);
+       l &= ~OTG_IDLE_EN;
+       omap_writel(l, OTG_SYSCON_1);
+       udelay(100);
+
+       /* some of these values are board-specific... */
+       l = omap_readl(OTG_SYSCON_2);
+       l |= OTG_EN
+               /* for B-device: */
+               | SRP_GPDATA            /* 9msec Bdev D+ pulse */
+               | SRP_GPDVBUS           /* discharge after VBUS pulse */
+               // | (3 << 24)          /* 2msec VBUS pulse */
+               /* for A-device: */
+               | (0 << 20)             /* 200ms nominal A_WAIT_VRISE timer */
+               | SRP_DPW               /* detect 167+ns SRP pulses */
+               | SRP_DATA | SRP_VBUS;  /* accept both kinds of SRP pulse */
+       omap_writel(l, OTG_SYSCON_2);
+
+       omap_writew(DRIVER_SWITCH | OPRT_CHG
+                       | B_SRP_TMROUT | B_HNP_FAIL
+                                 | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT,
+                                       OTG_IRQ_EN);
+       l = omap_readl(OTG_SYSCON_2);
+       l |= OTG_EN;
+       omap_writel(l, OTG_SYSCON_2);
+
+       return 0;
+}
+
+static int omap_otg_probe(struct device *dev)
+{
+       int ret;
+
+       tahvo_otg_dev = to_platform_device(dev);
+       ret = omap_otg_init();
+       if (ret != 0) {
+               printk(KERN_ERR "tahvo-usb: omap_otg_init failed\n");
+               return ret;
+       }
+
+       return request_irq(tahvo_otg_dev->resource[1].start,
+                          omap_otg_irq, IRQF_DISABLED, DRIVER_NAME,
+                          &tahvo_usb_device);
+}
+
+static int omap_otg_remove(struct device *dev)
+{
+       free_irq(tahvo_otg_dev->resource[1].start, &tahvo_usb_device);
+       tahvo_otg_dev = NULL;
+
+       return 0;
+}
+
+struct device_driver omap_otg_driver = {
+       .name           = "omap_otg",
+       .bus            = &platform_bus_type,
+       .probe          = omap_otg_probe,
+       .remove         = omap_otg_remove,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Tahvo related functions
+ * These are Nokia proprietary code, except for the OTG register settings,
+ * which are copied from isp1301.c
+ * ---------------------------------------------------------------------------
+ */
+static ssize_t vbus_state_show(struct device *device,
+                              struct device_attribute *attr, char *buf)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       return sprintf(buf, "%d\n", tu->vbus_state);
+}
+static DEVICE_ATTR(vbus_state, 0444, vbus_state_show, NULL);
+
+int vbus_active = 0;
+
+#if 0
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+       struct device   *dev;
+
+       if (!tu->otg.host)
+               return -ENODEV;
+
+       /* Currently ASSUMES only the OTG port matters;
+        * other ports could be active...
+        */
+       dev = tu->otg.host->controller;
+       return dev->driver->suspend(dev, PMSG_SUSPEND);
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+       struct device   *dev;
+
+       if (!tu->otg.host)
+               return -ENODEV;
+
+       dev = tu->otg.host->controller;
+       return dev->driver->resume(dev);
+}
+
+#else
+
+static int host_suspend(struct tahvo_usb *tu)
+{
+       return 0;
+}
+
+static int host_resume(struct tahvo_usb *tu)
+{
+       return 0;
+}
+
+#endif
+
+static void check_vbus_state(struct tahvo_usb *tu)
+{
+       int reg, prev_state;
+
+       reg = tahvo_read_reg(TAHVO_REG_IDSR);
+       if (reg & 0x01) {
+               u32 l;
+
+               vbus_active = 1;
+               switch (tu->otg.state) {
+               case OTG_STATE_B_IDLE:
+                       /* Enable the gadget driver */
+                       if (tu->otg.gadget)
+                               usb_gadget_vbus_connect(tu->otg.gadget);
+                       /* Set B-session valid and not B-sessio ended to indicate
+                        * Vbus to be ok. */
+                       l = omap_readl(OTG_CTRL);
+                       l &= ~OTG_BSESSEND;
+                       l |= OTG_BSESSVLD;
+                       omap_writel(l, OTG_CTRL);
+
+                       tu->otg.state = OTG_STATE_B_PERIPHERAL;
+                       break;
+               case OTG_STATE_A_IDLE:
+                       /* Session is now valid assuming the USB hub is driving Vbus */
+                       tu->otg.state = OTG_STATE_A_HOST;
+                       host_resume(tu);
+                       break;
+               default:
+                       break;
+               }
+               printk("USB cable connected\n");
+       } else {
+               switch (tu->otg.state) {
+               case OTG_STATE_B_PERIPHERAL:
+                       if (tu->otg.gadget)
+                               usb_gadget_vbus_disconnect(tu->otg.gadget);
+                       tu->otg.state = OTG_STATE_B_IDLE;
+                       break;
+               case OTG_STATE_A_HOST:
+                       tu->otg.state = OTG_STATE_A_IDLE;
+                       break;
+               default:
+                       break;
+               }
+               printk("USB cable disconnected\n");
+               vbus_active = 0;
+       }
+
+       prev_state = tu->vbus_state;
+       tu->vbus_state = reg & 0x01;
+       if (prev_state != tu->vbus_state)
+               sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
+}
+
+static void tahvo_usb_become_host(struct tahvo_usb *tu)
+{
+       u32 l;
+
+       /* Clear system and transceiver controlled bits
+        * also mark the A-session is always valid */
+       omap_otg_init();
+
+       l = omap_readl(OTG_CTRL);
+       l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK);
+       l |= OTG_ASESSVLD;
+       omap_writel(l, OTG_CTRL);
+
+       /* Power up the transceiver in USB host mode */
+       tahvo_write_reg(TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
+                       USBR_MASTER_SW2 | USBR_MASTER_SW1);
+       tu->otg.state = OTG_STATE_A_IDLE;
+
+       check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_host(struct tahvo_usb *tu)
+{
+       host_suspend(tu);
+       tu->otg.state = OTG_STATE_A_IDLE;
+}
+
+static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
+{
+       u32 l;
+
+       /* Clear system and transceiver controlled bits
+        * and enable ID to mark peripheral mode and
+        * BSESSEND to mark no Vbus */
+       omap_otg_init();
+       l = omap_readl(OTG_CTRL);
+       l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+       l |= OTG_ID | OTG_BSESSEND;
+       omap_writel(l, OTG_CTRL);
+
+       /* Power up transceiver and set it in USB perhiperal mode */
+       tahvo_write_reg(TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | USBR_NSUSPEND | USBR_SLAVE_SW);
+       tu->otg.state = OTG_STATE_B_IDLE;
+
+       check_vbus_state(tu);
+}
+
+static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu)
+{
+       u32 l;
+
+       l = omap_readl(OTG_CTRL);
+       l &= ~OTG_BSESSVLD;
+       l |= OTG_BSESSEND;
+       omap_writel(l, OTG_CTRL);
+
+       if (tu->otg.gadget)
+               usb_gadget_vbus_disconnect(tu->otg.gadget);
+       tu->otg.state = OTG_STATE_B_IDLE;
+
+}
+
+static void tahvo_usb_power_off(struct tahvo_usb *tu)
+{
+       u32 l;
+       int id;
+
+       /* Disable gadget controller if any */
+       if (tu->otg.gadget)
+               usb_gadget_vbus_disconnect(tu->otg.gadget);
+
+       host_suspend(tu);
+
+       /* Disable OTG and interrupts */
+       if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+               id = OTG_ID;
+       else
+               id = 0;
+       l = omap_readl(OTG_CTRL);
+       l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD);
+       l |= id | OTG_BSESSEND;
+       omap_writel(l, OTG_CTRL);
+       omap_writew(0, OTG_IRQ_EN);
+
+       l = omap_readl(OTG_SYSCON_2);
+       l &= ~OTG_EN;
+       omap_writel(l, OTG_SYSCON_2);
+
+       l = omap_readl(OTG_SYSCON_1);
+       l |= OTG_IDLE_EN;
+       omap_writel(l, OTG_SYSCON_1);
+
+       /* Power off transceiver */
+       tahvo_write_reg(TAHVO_REG_USBR, 0);
+       tu->otg.state = OTG_STATE_UNDEFINED;
+}
+
+
+static int tahvo_usb_set_power(struct otg_transceiver *dev, unsigned mA)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "set_power %d mA\n", mA);
+
+       if (dev->state == OTG_STATE_B_PERIPHERAL) {
+               /* REVISIT: Can Tahvo charge battery from VBUS? */
+       }
+       return 0;
+}
+
+static int tahvo_usb_set_suspend(struct otg_transceiver *dev, int suspend)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+       u16 w;
+
+       dev_dbg(&tu->pt_dev->dev, "set_suspend\n");
+
+       w = tahvo_read_reg(TAHVO_REG_USBR);
+       if (suspend)
+               w &= ~USBR_NSUSPEND;
+       else
+               w |= USBR_NSUSPEND;
+       tahvo_write_reg(TAHVO_REG_USBR, w);
+
+       return 0;
+}
+
+static int tahvo_usb_start_srp(struct otg_transceiver *dev)
+{
+       struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, otg);
+       u32 otg_ctrl;
+
+       dev_dbg(&tu->pt_dev->dev, "start_srp\n");
+
+       if (!dev || tu->otg.state != OTG_STATE_B_IDLE)
+               return -ENODEV;
+
+       otg_ctrl = omap_readl(OTG_CTRL);
+       if (!(otg_ctrl & OTG_BSESSEND))
+               return -EINVAL;
+
+       otg_ctrl |= OTG_B_BUSREQ;
+       otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_SYS_MASK;
+       omap_writel(otg_ctrl, OTG_CTRL);
+       tu->otg.state = OTG_STATE_B_SRP_INIT;
+
+       return 0;
+}
+
+static int tahvo_usb_start_hnp(struct otg_transceiver *otg)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "start_hnp\n");
+#ifdef CONFIG_USB_OTG
+       /* REVISIT: Add this for OTG */
+#endif
+       return -EINVAL;
+}
+
+static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+       u32 l;
+
+       dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host);
+
+       if (otg == NULL)
+               return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP)
+
+       mutex_lock(&tu->serialize);
+
+       if (host == NULL) {
+               if (TAHVO_MODE(tu) == TAHVO_MODE_HOST)
+                       tahvo_usb_power_off(tu);
+               tu->otg.host = NULL;
+               mutex_unlock(&tu->serialize);
+               return 0;
+       }
+
+       l = omap_readl(OTG_SYSCON_1);
+       l &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN);
+       omap_writel(l, OTG_SYSCON_1);
+
+       if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) {
+               tu->otg.host = NULL;
+               tahvo_usb_become_host(tu);
+       } else
+               host_suspend(tu);
+
+       tu->otg.host = host;
+
+       mutex_unlock(&tu->serialize);
+#else
+       /* No host mode configured, so do not allow host controlled to be set */
+       return -EINVAL;
+#endif
+
+       return 0;
+}
+
+static int tahvo_usb_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+{
+       struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg);
+
+       dev_dbg(&tu->pt_dev->dev, "set_peripheral %p\n", gadget);
+
+       if (!otg)
+               return -ENODEV;
+
+#if defined(CONFIG_USB_OTG) || defined(CONFIG_USB_GADGET_OMAP)
+
+       mutex_lock(&tu->serialize);
+
+       if (!gadget) {
+               if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+                       tahvo_usb_power_off(tu);
+               tu->otg.gadget = NULL;
+               mutex_unlock(&tu->serialize);
+               return 0;
+       }
+
+       tu->otg.gadget = gadget;
+       if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL)
+               tahvo_usb_become_peripheral(tu);
+
+       mutex_unlock(&tu->serialize);
+#else
+       /* No gadget mode configured, so do not allow host controlled to be set */
+       return -EINVAL;
+#endif
+
+       return 0;
+}
+
+static void tahvo_usb_irq_work(struct work_struct *work)
+{
+       struct tahvo_usb *tu = container_of(work, struct tahvo_usb, irq_work);
+
+       mutex_lock(&tu->serialize);
+       check_vbus_state(tu);
+       mutex_unlock(&tu->serialize);
+}
+
+static void tahvo_usb_vbus_interrupt(unsigned long arg)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb *) arg;
+
+       tahvo_ack_irq(TAHVO_INT_VBUSON);
+       /* Seems we need this to acknowledge the interrupt */
+       tahvo_read_reg(TAHVO_REG_IDSR);
+       schedule_work(&tu->irq_work);
+}
+
+#ifdef CONFIG_USB_OTG
+static ssize_t otg_mode_show(struct device *device,
+                            struct device_attribute *attr, char *buf)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       switch (tu->tahvo_mode) {
+       case TAHVO_MODE_HOST:
+               return sprintf(buf, "host\n");
+       case TAHVO_MODE_PERIPHERAL:
+               return sprintf(buf, "peripheral\n");
+       }
+       return sprintf(buf, "unknown\n");
+}
+
+static ssize_t otg_mode_store(struct device *device,
+                             struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       struct tahvo_usb *tu = (struct tahvo_usb*) device->driver_data;
+       int r;
+
+       r = strlen(buf);
+       mutex_lock(&tu->serialize);
+       if (strncmp(buf, "host", 4) == 0) {
+               if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL)
+                       tahvo_usb_stop_peripheral(tu);
+               tu->tahvo_mode = TAHVO_MODE_HOST;
+               if (tu->otg.host) {
+                       printk(KERN_INFO "Selected HOST mode: host controller present.\n");
+                       tahvo_usb_become_host(tu);
+               } else {
+                       printk(KERN_INFO "Selected HOST mode: no host controller, powering off.\n");
+                       tahvo_usb_power_off(tu);
+               }
+       } else if (strncmp(buf, "peripheral", 10) == 0) {
+               if (tu->tahvo_mode == TAHVO_MODE_HOST)
+                       tahvo_usb_stop_host(tu);
+               tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+               if (tu->otg.gadget) {
+                       printk(KERN_INFO "Selected PERIPHERAL mode: gadget driver present.\n");
+                       tahvo_usb_become_peripheral(tu);
+               } else {
+                       printk(KERN_INFO "Selected PERIPHERAL mode: no gadget driver, powering off.\n");
+                       tahvo_usb_power_off(tu);
+               }
+       } else
+               r = -EINVAL;
+
+       mutex_unlock(&tu->serialize);
+       return r;
+}
+
+static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store);
+#endif
+
+static int tahvo_usb_probe(struct device *dev)
+{
+       struct tahvo_usb *tu;
+       int ret;
+
+       dev_dbg(dev, "probe\n");
+
+       /* Create driver data */
+       tu = kmalloc(sizeof(*tu), GFP_KERNEL);
+       if (!tu)
+               return -ENOMEM;
+       memset(tu, 0, sizeof(*tu));
+       tu->pt_dev = container_of(dev, struct platform_device, dev);
+#ifdef CONFIG_USB_OTG
+       /* Default mode */
+#ifdef CONFIG_CBUS_TAHVO_USB_HOST_BY_DEFAULT
+       tu->tahvo_mode = TAHVO_MODE_HOST;
+#else
+       tu->tahvo_mode = TAHVO_MODE_PERIPHERAL;
+#endif
+#endif
+
+       INIT_WORK(&tu->irq_work, tahvo_usb_irq_work);
+       mutex_init(&tu->serialize);
+
+       /* Set initial state, so that we generate kevents only on
+        * state changes */
+       tu->vbus_state = tahvo_read_reg(TAHVO_REG_IDSR) & 0x01;
+
+       /* We cannot enable interrupt until omap_udc is initialized */
+       ret = tahvo_request_irq(TAHVO_INT_VBUSON, tahvo_usb_vbus_interrupt,
+                               (unsigned long) tu, "vbus_interrupt");
+       if (ret != 0) {
+               kfree(tu);
+               printk(KERN_ERR "Could not register Tahvo interrupt for VBUS\n");
+               return ret;
+       }
+
+       /* Attributes */
+       ret = device_create_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+       ret |= device_create_file(dev, &dev_attr_otg_mode);
+#endif
+       if (ret)
+               printk(KERN_ERR "attribute creation failed: %d\n", ret);
+
+       /* Create OTG interface */
+       tahvo_usb_power_off(tu);
+       tu->otg.state = OTG_STATE_UNDEFINED;
+       tu->otg.label = DRIVER_NAME;
+       tu->otg.set_host = tahvo_usb_set_host;
+       tu->otg.set_peripheral = tahvo_usb_set_peripheral;
+       tu->otg.set_power = tahvo_usb_set_power;
+       tu->otg.set_suspend = tahvo_usb_set_suspend;
+       tu->otg.start_srp = tahvo_usb_start_srp;
+       tu->otg.start_hnp = tahvo_usb_start_hnp;
+
+       ret = otg_set_transceiver(&tu->otg);
+       if (ret < 0) {
+               printk(KERN_ERR "Cannot register USB transceiver\n");
+               kfree(tu);
+               tahvo_free_irq(TAHVO_INT_VBUSON);
+               return ret;
+       }
+
+       dev->driver_data = tu;
+
+       /* Act upon current vbus state once at startup. A vbus state irq may or
+        * may not be generated in addition to this. */
+       schedule_work(&tu->irq_work);
+       return 0;
+}
+
+static int tahvo_usb_remove(struct device *dev)
+{
+       dev_dbg(dev, "remove\n");
+
+       tahvo_free_irq(TAHVO_INT_VBUSON);
+       flush_scheduled_work();
+       otg_set_transceiver(0);
+       device_remove_file(dev, &dev_attr_vbus_state);
+#ifdef CONFIG_USB_OTG
+       device_remove_file(dev, &dev_attr_otg_mode);
+#endif
+       return 0;
+}
+
+static struct device_driver tahvo_usb_driver = {
+       .name           = "tahvo-usb",
+       .bus            = &platform_bus_type,
+       .probe          = tahvo_usb_probe,
+       .remove         = tahvo_usb_remove,
+};
+
+static struct platform_device tahvo_usb_device = {
+       .name           = "tahvo-usb",
+       .id             = -1,
+};
+
+static int __init tahvo_usb_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "Tahvo USB transceiver driver initializing\n");
+       ret = driver_register(&tahvo_usb_driver);
+       if (ret)
+               return ret;
+       ret = platform_device_register(&tahvo_usb_device);
+       if (ret < 0) {
+               driver_unregister(&tahvo_usb_driver);
+               return ret;
+       }
+       ret = driver_register(&omap_otg_driver);
+       if (ret) {
+               platform_device_unregister(&tahvo_usb_device);
+               driver_unregister(&tahvo_usb_driver);
+               return ret;
+       }
+       return 0;
+}
+
+subsys_initcall(tahvo_usb_init);
+
+static void __exit tahvo_usb_exit(void)
+{
+       driver_unregister(&omap_otg_driver);
+       platform_device_unregister(&tahvo_usb_device);
+       driver_unregister(&tahvo_usb_driver);
+}
+module_exit(tahvo_usb_exit);
+
+MODULE_DESCRIPTION("Tahvo USB OTG Transceiver Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs");
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..5876b68
--- /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 <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/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), IRQ_TYPE_EDGE_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 51738bdd834eccd732eb234b8cddd7cb1c83ed61..dffaf46a9afd843fd90c37e0804531bfa5d662f2 100644 (file)
@@ -118,18 +118,21 @@ static int __init omap_rng_probe(struct platform_device *pdev)
 
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
+       if (mem == NULL) {
+               ret = -EBUSY;
+               goto err_region;
+       }
 
        dev_set_drvdata(&pdev->dev, mem);
-       rng_base = (u32 __force __iomem *)io_p2v(res->start);
+       rng_base = ioremap(res->start, res->end - res->start + 1);
+       if (!rng_base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
 
        ret = hwrng_register(&omap_rng_ops);
-       if (ret) {
-               release_resource(mem);
-               rng_base = NULL;
-               return ret;
-       }
+       if (ret)
+               goto err_register;
 
        dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n",
                omap_rng_read_reg(RNG_REV_REG));
@@ -138,6 +141,18 @@ static int __init omap_rng_probe(struct platform_device *pdev)
        rng_dev = pdev;
 
        return 0;
+
+err_register:
+       iounmap(rng_base);
+       rng_base = NULL;
+err_ioremap:
+       release_resource(mem);
+err_region:
+       if (cpu_is_omap24xx()) {
+               clk_disable(rng_ick);
+               clk_put(rng_ick);
+       }
+       return ret;
 }
 
 static int __exit omap_rng_remove(struct platform_device *pdev)
@@ -148,6 +163,8 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
 
        omap_rng_write_reg(RNG_MASK_REG, 0x0);
 
+       iounmap(rng_base);
+
        if (cpu_is_omap24xx()) {
                clk_disable(rng_ick);
                clk_put(rng_ick);
@@ -188,7 +205,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
@@ -199,7 +215,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)
index e522144cba3af9bc9d9e5e9bbc1e5dcb05e693c0..7fb9494e4d80d5757b4f6185795fa647c0fad104 100644 (file)
@@ -83,6 +83,13 @@ config ZCRYPT_MONOLITHIC
          that contains all parts of the crypto device driver (ap bus,
          request router and all the card drivers).
 
+config OMAP_SHA1_MD5
+       tristate "Support for OMAP SHA1/MD5 hw engine"
+       depends on ARCH_OMAP24XX && CRYPTO_SHA1 && CRYPTO_MD5
+       help
+         OMAP processors have SHA1/MD5 module accelerator. Select this if you
+         want to use the OMAP module for SHA1/MD5 algorithms.
+
 config CRYPTO_SHA1_S390
        tristate "SHA1 digest algorithm"
        depends on S390
index 73557b2968d33710ae4c0a5745d6ac4bce0dedef..5da41a156fc7871d6a399d6eb90a00ff754de51a 100644 (file)
@@ -1,6 +1,7 @@
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
+obj-$(CONFIG_OMAP_SHA1_MD5) += omap-sha1-md5.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
 obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
 obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
diff --git a/drivers/crypto/omap-sha1-md5.c b/drivers/crypto/omap-sha1-md5.c
new file mode 100644 (file)
index 0000000..6d77703
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for OMAP SHA1/MD5 HW acceleration.
+ *
+ * Copyright (c) 2007 Instituto Nokia de Tecnologia - INdT
+ * Author: David Cohen <david.cohen@indt.org.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This driver is based on padlock-sha.c driver.
+ */
+
+#include <asm/arch-omap/irqs.h>
+#include <crypto/algapi.h>
+#include <crypto/sha.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/cryptohash.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+
+#define SHA_REG_DIGEST(x)              (0x00 + ((x) * 0x04))
+#define SHA_REG_DIN(x)                 (0x1C + ((x) * 0x04))
+
+#define SHA1_MD5_BLOCK_SIZE            SHA1_BLOCK_SIZE
+#define MD5_DIGEST_SIZE                        16
+
+#define SHA_REG_DIGCNT                 0x14
+
+#define SHA_REG_CTRL                   0x18
+#define SHA_REG_CTRL_LENGTH            (0xFFFFFFFF << 5)
+#define SHA_REG_CTRL_CLOSE_HASH                (1 << 4)
+#define SHA_REG_CTRL_ALGO_CONST                (1 << 3)
+#define SHA_REG_CTRL_ALGO              (1 << 2)
+#define SHA_REG_CTRL_INPUT_READY       (1 << 1)
+#define SHA_REG_CTRL_OUTPUT_READY      (1 << 0)
+
+#define SHA_REG_REV                    0x5C
+#define SHA_REG_REV_MAJOR              0xF0
+#define SHA_REG_REV_MINOR              0x0F
+
+#define SHA_REG_MASK                   0x60
+#define SHA_REG_MASK_DMA_EN            (1 << 3)
+#define SHA_REG_MASK_IT_EN             (1 << 2)
+#define SHA_REG_MASK_SOFTRESET         (1 << 1)
+#define SHA_REG_AUTOIDLE               (1 << 0)
+
+#define SHA_REG_SYSSTATUS              0x64
+#define SHA_REG_SYSSTATUS_RESETDONE    (1 << 0)
+
+#define DRIVER_NAME                    "OMAP SHA1/MD5"
+
+struct omap_sha1_md5_ctx {
+       unsigned int            type_algo;
+       unsigned int            bufcnt;
+       unsigned int            digcnt;
+       int                     algo_const;
+       int                     bypass;
+       int                     digsize;
+       u8                      hash[SHA1_DIGEST_SIZE];
+       u8                      buffer[SHA1_BLOCK_SIZE];
+       struct                  hash_desc fallback;
+};
+
+struct omap_sha1_md5_dev {
+       unsigned long           base_address;
+       int                     irq;
+       int                     digready;
+       struct clk              *sha1_ick;
+       struct omap_sha1_md5_ctx
+                               *hw_ctx;
+       struct device           *dev;
+       wait_queue_head_t       wq;
+};
+
+static struct omap_sha1_md5_dev *sha1_md5_data;
+
+#define SHA_REG_IOADDR(d, x) (void *)IO_ADDRESS((d)->base_address + (x))
+
+static u32 omap_sha1_md5_read(struct omap_sha1_md5_dev *data, u32 offset)
+{
+       return __raw_readl(SHA_REG_IOADDR(data, offset));
+}
+
+static void omap_sha1_md5_write(struct omap_sha1_md5_dev *data,
+                                       u32 value, u32 offset)
+{
+       __raw_writel(value, SHA_REG_IOADDR(data, offset));
+}
+
+static void omap_sha1_md5_write_mask(struct omap_sha1_md5_dev *data,
+                                       u32 value, u32 mask, u32 address)
+{
+       u32 val;
+
+       val = omap_sha1_md5_read(data, address);
+       val &= ~mask;
+       val |= value;
+       omap_sha1_md5_write(data, val, address);
+}
+
+static inline void omap_sha1_md5_enable_clk(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+       clk_enable(data->sha1_ick);
+}
+
+static inline void omap_sha1_md5_disable_clk(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+       clk_disable(data->sha1_ick);
+}
+
+static void omap_sha1_md5_copy_hash(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+       u32 *hash = (u32 *)ctx->hash;
+
+       if (ctx->type_algo) {
+               /* SHA1 results are in big endian */
+               hash[0] = be32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(0)));
+               hash[1] = be32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(1)));
+               hash[2] = be32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(2)));
+               hash[3] = be32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(3)));
+               hash[4] = be32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(4)));
+       } else {
+               /* MD5 results are in little endian */
+               hash[0] = le32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(0)));
+               hash[1] = le32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(1)));
+               hash[2] = le32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(2)));
+               hash[3] = le32_to_cpu(
+                               omap_sha1_md5_read(data, SHA_REG_DIGEST(3)));
+       }
+}
+
+static void omap_sha1_md5_bypass(struct crypto_tfm *tfm,
+                               u8 *data, unsigned int length)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (unlikely(!ctx->bypass))
+               return;
+
+       if (ctx->bypass == 1) {
+               crypto_hash_init(&ctx->fallback);
+               ctx->bypass++;
+       }
+
+       if (length) {
+               struct scatterlist sg;
+
+               sg_set_buf(&sg, data, length);
+               crypto_hash_update(&ctx->fallback, &sg, sg.length);
+       }
+}
+
+static void omap_sha1_md5_digest_buffer(struct crypto_tfm *tfm,
+                               u8 *buf, unsigned int len, int close_hash)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+       unsigned int algo_const = 0;
+       int c;
+       u32 *buffer = (u32 *)buf;
+
+       if (unlikely(ctx->bypass)) {
+               omap_sha1_md5_bypass(tfm, buf, len);
+               return;
+       }
+
+       if (unlikely(ctx->algo_const)) {
+               algo_const = SHA_REG_CTRL_ALGO_CONST;
+               ctx->algo_const = 0;
+       } else
+               omap_sha1_md5_write(data, ctx->digcnt, SHA_REG_DIGCNT);
+
+       if (unlikely(close_hash))
+               close_hash = SHA_REG_CTRL_CLOSE_HASH;
+
+       /* Setting ALGO_CONST only for the first iteration
+        * and CLOSE_HASH only for the last one. */
+       omap_sha1_md5_write_mask(data,
+                       ctx->type_algo | algo_const | close_hash | (len << 5),
+                       SHA_REG_CTRL_ALGO_CONST | SHA_REG_CTRL_CLOSE_HASH |
+                       SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH,
+                       SHA_REG_CTRL);
+
+       ctx->digcnt += len;
+       while (!(omap_sha1_md5_read(data, SHA_REG_CTRL)
+               & SHA_REG_CTRL_INPUT_READY));
+
+       if (len % 4)
+               len = (len/4) + 1;
+       else
+               len /= 4;
+       for (c = 0; c < len; c++)
+               omap_sha1_md5_write(data, buffer[c], SHA_REG_DIN(c));
+}
+
+static void omap_sha1_md5_append_buffer(struct crypto_tfm *tfm,
+                               const uint8_t *data, unsigned int length)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       BUG_ON((ctx->bufcnt + length) > SHA1_MD5_BLOCK_SIZE);
+
+       memcpy(&ctx->buffer[ctx->bufcnt], data, length);
+       ctx->bufcnt += length;
+}
+
+static void omap_sha1_md5_dia_update(struct crypto_tfm *tfm,
+                               const uint8_t *data, unsigned int length)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       /* We need to save the last buffer <= 64 to digest it with
+        * CLOSE_HASH = 1 */
+       if (ctx->bufcnt && ((ctx->bufcnt + length) > SHA1_MD5_BLOCK_SIZE)) {
+               unsigned int c = SHA1_MD5_BLOCK_SIZE - ctx->bufcnt;
+
+               omap_sha1_md5_append_buffer(tfm, data, c);
+               data += c;
+               length -= c;
+               if (length) {
+                       ctx->bufcnt = 0;
+                       omap_sha1_md5_digest_buffer(tfm, ctx->buffer,
+                                       SHA1_MD5_BLOCK_SIZE, 0);
+               }
+       }
+
+       while (length > SHA1_MD5_BLOCK_SIZE) {
+               /* Revisit: use DMA here */
+               omap_sha1_md5_digest_buffer(tfm, (u8 *)data,
+                               SHA1_MD5_BLOCK_SIZE, 0);
+               length -= SHA1_MD5_BLOCK_SIZE;
+               data += SHA1_MD5_BLOCK_SIZE;
+       }
+
+       if (length)
+               omap_sha1_md5_append_buffer(tfm, data, length);
+}
+
+static void omap_sha1_md5_start_reset(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+       omap_sha1_md5_write_mask(data, SHA_REG_MASK_SOFTRESET,
+                       SHA_REG_MASK_SOFTRESET, SHA_REG_MASK);
+}
+
+static void omap_sha1_md5_wait_reset(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+
+       while (!(omap_sha1_md5_read(data, SHA_REG_SYSSTATUS)
+                       & SHA_REG_SYSSTATUS_RESETDONE));
+}
+
+static void omap_sha1_md5_dia_init(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       if (unlikely(data->hw_ctx))
+               ctx->bypass = 1;
+       else {
+               data->hw_ctx = ctx;
+               ctx->bypass = 0;
+               omap_sha1_md5_enable_clk(tfm);
+               omap_sha1_md5_start_reset(tfm);
+               data->digready = 0;
+       }
+
+       if (ctx->bypass) {
+               omap_sha1_md5_bypass(tfm, NULL, 0);
+               return;
+       }
+
+       ctx->algo_const = 1;
+       ctx->bufcnt = 0;
+       ctx->digcnt = 0;
+
+       omap_sha1_md5_wait_reset(tfm);
+       omap_sha1_md5_write_mask(data, SHA_REG_MASK_IT_EN,
+               SHA_REG_MASK_DMA_EN | SHA_REG_MASK_IT_EN, SHA_REG_MASK);
+}
+
+static void omap_sha1_md5_dia_final(struct crypto_tfm *tfm, uint8_t *out)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+       int digsize = ctx->digsize;
+
+       /* The buffer should be >= 9 */
+       if (((ctx->digcnt + ctx->bufcnt) < 9) && !ctx->bypass)
+               ctx->bypass = 1;
+
+       omap_sha1_md5_digest_buffer(tfm, ctx->buffer, ctx->bufcnt, 1);
+
+       if (unlikely(ctx->bypass)) {
+               crypto_hash_final(&ctx->fallback, out);
+               ctx->bypass = 0;
+               goto bypass;
+       } else
+               data->digready = 1;
+
+       wait_event_interruptible(data->wq, (data->digready == 2));
+       omap_sha1_md5_copy_hash(tfm);
+
+       memcpy(out, ctx->hash, digsize);
+
+bypass:
+       if (data->hw_ctx == ctx) {
+               omap_sha1_md5_disable_clk(tfm);
+               data->hw_ctx = NULL;
+       }
+}
+
+static irqreturn_t omap_sha1_md5_irq(int irq, void *dev_id)
+{
+       struct omap_sha1_md5_dev *data = dev_id;
+
+       omap_sha1_md5_write_mask(data, SHA_REG_CTRL_OUTPUT_READY,
+                       SHA_REG_CTRL_OUTPUT_READY, SHA_REG_CTRL);
+
+       if (likely(!data->digready))
+               return IRQ_HANDLED;
+
+       if (data->hw_ctx == NULL) {
+               dev_err(data->dev, "unknown interrupt.\n");
+               return IRQ_HANDLED;
+       }
+
+       data->digready = 2;
+       wake_up_interruptible(&data->wq);
+
+       return IRQ_HANDLED;
+}
+
+static int omap_sha1_md5_cra_init(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct omap_sha1_md5_dev *data = sha1_md5_data;
+       const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+       struct crypto_hash *fallback_tfm;
+
+       /* Allocate a fallback and abort if it failed. */
+       fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
+                                        CRYPTO_ALG_ASYNC |
+                                        CRYPTO_ALG_NEED_FALLBACK);
+       if (IS_ERR(fallback_tfm)) {
+               dev_err(data->dev, "fallback driver '%s' could not be"
+                               "loaded.\n", fallback_driver_name);
+               return PTR_ERR(fallback_tfm);
+       }
+
+       ctx->fallback.tfm = fallback_tfm;
+
+       return 0;
+}
+
+static int omap_sha1_cra_init(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->type_algo = SHA_REG_CTRL_ALGO;
+       ctx->digsize = SHA1_DIGEST_SIZE;
+
+       return omap_sha1_md5_cra_init(tfm);
+}
+
+static int omap_md5_cra_init(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       ctx->type_algo = 0;
+       ctx->digsize = MD5_DIGEST_SIZE;
+
+       return omap_sha1_md5_cra_init(tfm);
+}
+
+static void omap_sha1_md5_cra_exit(struct crypto_tfm *tfm)
+{
+       struct omap_sha1_md5_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       crypto_free_hash(ctx->fallback.tfm);
+       ctx->fallback.tfm = NULL;
+}
+
+static struct crypto_alg omap_sha1_alg = {
+       .cra_name               =       "sha1",
+       .cra_driver_name        =       "omap-sha1",
+       .cra_flags              =       CRYPTO_ALG_TYPE_DIGEST |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+       .cra_blocksize          =       SHA1_MD5_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct omap_sha1_md5_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(omap_sha1_alg.cra_list),
+       .cra_init               =       omap_sha1_cra_init,
+       .cra_exit               =       omap_sha1_md5_cra_exit,
+       .cra_u                  =       {
+               .digest = {
+                       .dia_digestsize =       SHA1_DIGEST_SIZE,
+                       .dia_init       =       omap_sha1_md5_dia_init,
+                       .dia_update     =       omap_sha1_md5_dia_update,
+                       .dia_final      =       omap_sha1_md5_dia_final,
+               }
+       }
+};
+
+static struct crypto_alg omap_md5_alg = {
+       .cra_name               =       "md5",
+       .cra_driver_name        =       "omap-md5",
+       .cra_flags              =       CRYPTO_ALG_TYPE_DIGEST |
+                                       CRYPTO_ALG_NEED_FALLBACK,
+       .cra_blocksize          =       SHA1_MD5_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct omap_sha1_md5_ctx),
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(omap_md5_alg.cra_list),
+       .cra_init               =       omap_md5_cra_init,
+       .cra_exit               =       omap_sha1_md5_cra_exit,
+       .cra_u                  =       {
+               .digest = {
+                       .dia_digestsize =       MD5_DIGEST_SIZE,
+                       .dia_init       =       omap_sha1_md5_dia_init,
+                       .dia_update     =       omap_sha1_md5_dia_update,
+                       .dia_final      =       omap_sha1_md5_dia_final,
+               }
+       }
+};
+
+static int omap_sha1_md5_probe(struct platform_device *pdev)
+{
+       struct omap_sha1_md5_dev *data;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int rc;
+
+       rc = crypto_register_alg(&omap_sha1_alg);
+       if (rc)
+               goto sha1_err;
+       rc = crypto_register_alg(&omap_md5_alg);
+       if (rc)
+               goto md5_err;
+
+       data = kzalloc(sizeof(struct omap_sha1_md5_dev), GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(dev, "unable to alloc data struct.\n");
+               goto data_err;
+       }
+       platform_set_drvdata(pdev, data);
+       data->dev = dev;
+
+       /* Get the base address */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "invalid resource type\n");
+               rc = -ENODEV;
+               goto res_err;
+       }
+       data->base_address = res->start;
+
+       /* Set the private data */
+       sha1_md5_data = data;
+
+       /* Get the IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dev_err(dev, "invalid resource type\n");
+               rc = -ENODEV;
+               goto res_err;
+       }
+       data->irq = res->start;
+
+       rc = request_irq(res->start, omap_sha1_md5_irq,
+                       IRQF_TRIGGER_LOW, DRIVER_NAME, data);
+       if (rc) {
+               dev_err(dev, "unable to request irq.\n");
+               goto res_err;
+       }
+
+       /* Initializing the clock */
+       data->sha1_ick = clk_get(0, "sha_ick");
+       if (!data->sha1_ick) {
+               dev_err(dev, "clock intialization failed.\n");
+               rc = -ENODEV;
+               goto clk_err;
+       }
+
+       init_waitqueue_head(&data->wq);
+
+       dev_info(dev, "hw accel on OMAP rev %u.%u\n",
+               (omap_sha1_md5_read(data, SHA_REG_REV) & SHA_REG_REV_MAJOR)>>4,
+               omap_sha1_md5_read(data, SHA_REG_REV) & SHA_REG_REV_MINOR);
+
+       return 0;
+
+clk_err:
+       free_irq(data->irq, data);
+res_err:
+       kfree(data);
+data_err:
+       crypto_unregister_alg(&omap_md5_alg);
+md5_err:
+       crypto_unregister_alg(&omap_sha1_alg);
+sha1_err:
+       dev_err(dev, "initialization failed.\n");
+       return rc;
+}
+
+static int omap_sha1_md5_remove(struct platform_device *pdev)
+{
+       struct omap_sha1_md5_dev *data = platform_get_drvdata(pdev);
+
+       free_irq(data->irq, data);
+       kfree(data);
+       crypto_unregister_alg(&omap_sha1_alg);
+       crypto_unregister_alg(&omap_md5_alg);
+
+       return 0;
+}
+
+static struct platform_driver omap_sha1_md5_driver = {
+       .probe  = omap_sha1_md5_probe,
+       .remove = omap_sha1_md5_remove,
+       .driver = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap_sha1_md5_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&omap_sha1_md5_driver);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void __exit omap_sha1_md5_exit(void)
+{
+       platform_driver_unregister(&omap_sha1_md5_driver);
+}
+
+module_init(omap_sha1_md5_init);
+module_exit(omap_sha1_md5_exit);
+
+MODULE_DESCRIPTION("OMAP SHA1/MD5 hw acceleration support.");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Cohen");
diff --git a/drivers/dsp/dspgateway/Kconfig b/drivers/dsp/dspgateway/Kconfig
new file mode 100644 (file)
index 0000000..122164a
--- /dev/null
@@ -0,0 +1,24 @@
+
+config OMAP_DSP
+       tristate "OMAP DSP driver (DSP Gateway)"
+       depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP24XX
+       select OMAP_MMU_FWK
+       select OMAP_MBOX_FWK
+       help
+         This enables OMAP DSP driver, DSP Gateway.
+
+config OMAP_DSP_MBCMD_VERBOSE
+       bool "Mailbox Command Verbose LOG"
+       depends on OMAP_DSP
+       help
+          This enables kernel log output in the Mailbox command exchanges
+         in the DSP Gateway driver.
+
+config OMAP_DSP_FBEXPORT
+       bool "Framebuffer export to DSP"
+       depends on OMAP_DSP && FB
+       help
+          This enables to map the frame buffer to DSP.
+         By doing this, DSP can access the frame buffer directly without
+         bothering ARM.
+
diff --git a/drivers/dsp/dspgateway/Makefile b/drivers/dsp/dspgateway/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/drivers/dsp/dspgateway/dsp.h b/drivers/dsp/dspgateway/dsp.h
new file mode 100644 (file)
index 0000000..84e7cea
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_DSP_H
+#define __PLAT_OMAP_DSP_DSP_H
+
+#include "hardware_dsp.h"
+#include <mach/dsp_common.h>
+#include <mach/mmu.h>
+
+
+#ifdef CONFIG_ARCH_OMAP2
+#include "../../../arch/arm/mach-omap2/prm.h"
+#include "../../../arch/arm/mach-omap2/prm-regbits-24xx.h"
+#include "../../../arch/arm/mach-omap2/cm.h"
+#include "../../../arch/arm/mach-omap2/cm-regbits-24xx.h"
+#endif
+
+/*
+ * MAJOR device number: !! allocated arbitrary !!
+ */
+#define OMAP_DSP_CTL_MAJOR             96
+#define OMAP_DSP_TASK_MAJOR            97
+
+#define OLD_BINARY_SUPPORT     y
+
+#ifdef OLD_BINARY_SUPPORT
+#define MBREV_3_0      0x0017
+#define MBREV_3_2      0x0018
+#endif
+
+#define DSP_INIT_PAGE  0xfff000
+
+#ifdef CONFIG_ARCH_OMAP1
+/* idle program will be placed at IDLEPG_BASE. */
+#define IDLEPG_BASE    0xfffe00
+#define IDLEPG_SIZE    0x100
+#endif /* CONFIG_ARCH_OMAP1 */
+
+/* timeout value for DSP response */
+#define DSP_TIMEOUT    (10 * HZ)
+
+enum dsp_mem_type_e {
+       MEM_TYPE_CROSSING = -1,
+       MEM_TYPE_NONE = 0,
+       MEM_TYPE_DARAM,
+       MEM_TYPE_SARAM,
+       MEM_TYPE_EXTERN,
+};
+
+
+typedef int __bitwise arm_dsp_dir_t;
+#define DIR_A2D        ((__force arm_dsp_dir_t) 1)
+#define DIR_D2A        ((__force arm_dsp_dir_t) 2)
+
+enum cfgstat_e {
+       CFGSTAT_CLEAN = 0,
+       CFGSTAT_READY,
+       CFGSTAT_SUSPEND,
+       CFGSTAT_RESUME, /* request only */
+       CFGSTAT_MAX
+};
+
+enum errcode_e {
+       ERRCODE_WDT = 0,
+       ERRCODE_MMU,
+       ERRCODE_MAX
+};
+
+/* keep 2 entries for TID_FREE and TID_ANON */
+#define TASKDEV_MAX    254
+
+#define MK32(uw,lw)    (((u32)(uw)) << 16 | (lw))
+#define MKLONG(uw,lw)  (((unsigned long)(uw)) << 16 | (lw))
+#define MKVIRT(uw,lw)  dspword_to_virt(MKLONG((uw), (lw)));
+
+struct sync_seq {
+       u16 da_dsp;
+       u16 da_arm;
+       u16 ad_dsp;
+       u16 ad_arm;
+};
+
+struct mem_sync_struct {
+       struct sync_seq *DARAM;
+       struct sync_seq *SARAM;
+       struct sync_seq *SDRAM;
+};
+
+/* struct mbcmd and union mbcmd_hw must be compatible */
+struct mbcmd {
+       u32 data:16;
+       u32 cmd_l:8;
+       u32 cmd_h:7;
+       u32 seq:1;
+};
+
+#define MBCMD_INIT(h, l, d) { \
+               .cmd_h = (h), \
+               .cmd_l = (l), \
+               .data  = (d), \
+       }
+
+struct mb_exarg {
+       u8 tid;
+       int argc;
+       u16 *argv;
+};
+
+typedef u32 dsp_long_t;        /* must have ability to carry TADD_ABORTADR */
+
+extern void dsp_mbox_start(void);
+extern void dsp_mbox_stop(void);
+extern int dsp_mbox_config(void *p);
+extern int sync_with_dsp(u16 *syncwd, u16 tid, int try_cnt);
+extern int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 int recovery_flag);
+#define dsp_mbcmd_send(mb)             __dsp_mbcmd_send_exarg((mb), NULL, 0)
+#define dsp_mbcmd_send_exarg(mb, arg)  __dsp_mbcmd_send_exarg((mb), (arg), 0)
+extern int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                        wait_queue_head_t *q);
+#define dsp_mbcmd_send_and_wait(mb, q) \
+       dsp_mbcmd_send_and_wait_exarg((mb), NULL, (q))
+
+static inline int __mbcompose_send_exarg(u8 cmd_h, u8 cmd_l, u16 data,
+                                            struct mb_exarg *arg,
+                                            int recovery_flag)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return __dsp_mbcmd_send_exarg(&mb, arg, recovery_flag);
+}
+#define mbcompose_send(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 0)
+#define mbcompose_send_exarg(cmd_h, cmd_l, data, arg) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), arg, 0)
+#define mbcompose_send_recovery(cmd_h, cmd_l, data) \
+       __mbcompose_send_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), NULL, 1)
+
+static inline int __mbcompose_send_and_wait_exarg(u8 cmd_h, u8 cmd_l,
+                                                     u16 data,
+                                                     struct mb_exarg *arg,
+                                                     wait_queue_head_t *q)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       return dsp_mbcmd_send_and_wait_exarg(&mb, arg, q);
+}
+#define mbcompose_send_and_wait(cmd_h, cmd_l, data, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       NULL, (q))
+#define mbcompose_send_and_wait_exarg(cmd_h, cmd_l, data, arg, q) \
+       __mbcompose_send_and_wait_exarg(MBOX_CMD_DSP_##cmd_h, (cmd_l), (data), \
+                                       (arg), (q))
+
+extern struct ipbuf_head *bid_to_ipbuf(u16 bid);
+extern void ipbuf_start(void);
+extern void ipbuf_stop(void);
+extern int ipbuf_config(u16 ln, u16 lsz, void *base);
+extern int ipbuf_sys_config(void *p, arm_dsp_dir_t dir);
+extern int ipbuf_p_validate(void *p, arm_dsp_dir_t dir);
+extern struct ipbuf_head *get_free_ipbuf(u8 tid);
+extern void release_ipbuf(struct ipbuf_head *ipb_h);
+extern void balance_ipbuf(void);
+extern void unuse_ipbuf(struct ipbuf_head *ipb_h);
+extern void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h);
+
+#define release_ipbuf_pvt(ipbuf_pvt) \
+       do { \
+               (ipbuf_pvt)->s = TID_FREE; \
+       } while(0)
+
+extern int mbox_revision;
+
+extern int dsp_cfgstat_request(enum cfgstat_e st);
+extern enum cfgstat_e dsp_cfgstat_get_stat(void);
+extern int dsp_set_runlevel(u8 level);
+
+extern int dsp_task_config_all(u8 n);
+extern void dsp_task_unconfig_all(void);
+extern u8 dsp_task_count(void);
+extern int dsp_taskmod_busy(void);
+extern int dsp_mkdev(char *name);
+extern int dsp_rmdev(char *name);
+extern int dsp_tadd_minor(unsigned char minor, dsp_long_t adr);
+extern int dsp_tdel_minor(unsigned char minor);
+extern int dsp_tkill_minor(unsigned char minor);
+extern long taskdev_state_stale(unsigned char minor);
+extern int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz);
+extern void dsp_dbg_stop(void);
+
+extern int ipbuf_is_held(u8 tid, u16 bid);
+
+extern int dsp_mem_sync_inc(void);
+extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
+extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
+extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
+#ifdef CONFIG_ARCH_OMAP1
+extern void dsp_mem_usecount_clear(void);
+#endif
+extern void exmap_use(void *vadr, size_t len);
+extern void exmap_unuse(void *vadr, size_t len);
+extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
+extern void dsp_mem_start(void);
+extern void dsp_mem_stop(void);
+
+extern void dsp_twch_start(void);
+extern void dsp_twch_stop(void);
+extern void dsp_twch_touch(void);
+
+extern void dsp_err_start(void);
+extern void dsp_err_stop(void);
+extern void dsp_err_set(enum errcode_e code, unsigned long arg);
+extern void dsp_err_clear(enum errcode_e code);
+extern int dsp_err_isset(enum errcode_e code);
+
+enum cmd_l_type_e {
+       CMD_L_TYPE_NULL,
+       CMD_L_TYPE_TID,
+       CMD_L_TYPE_SUBCMD,
+};
+
+struct cmdinfo {
+       char *name;
+       enum cmd_l_type_e cmd_l_type;
+       void (*handler)(struct mbcmd *mb);
+};
+
+extern const struct cmdinfo *cmdinfo[];
+
+#define cmd_name(mb)   (cmdinfo[(mb).cmd_h]->name)
+extern char *subcmd_name(struct mbcmd *mb);
+
+extern void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir);
+
+extern struct omap_mmu dsp_mmu;
+
+#define dsp_mem_enable(addr)   omap_mmu_mem_enable(&dsp_mmu, (addr))
+#define dsp_mem_disable(addr)  omap_mmu_mem_disable(&dsp_mmu, (addr))
+
+#define DSPSPACE_SIZE  0x1000000
+
+#define omap_set_bit_regw(b,r) \
+       do { omap_writew(omap_readw(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regw(b,r) \
+       do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0)
+#define omap_set_bit_regl(b,r) \
+       do { omap_writel(omap_readl(r) | (b), (r)); } while(0)
+#define omap_clr_bit_regl(b,r) \
+       do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0)
+#define omap_set_bits_regl(val,mask,r) \
+       do { omap_writel((omap_readl(r) & ~(mask)) | (val), (r)); } while(0)
+
+#define dspword_to_virt(dw)    ((void *)(dspmem_base + ((dw) << 1)))
+#define dspbyte_to_virt(db)    ((void *)(dspmem_base + (db)))
+#define virt_to_dspword(va) \
+       ((dsp_long_t)(((unsigned long)(va) - dspmem_base) >> 1))
+#define virt_to_dspbyte(va) \
+       ((dsp_long_t)((unsigned long)(va) - dspmem_base))
+#define is_dsp_internal_mem(va) \
+       (((unsigned long)(va) >= dspmem_base) &&  \
+        ((unsigned long)(va) < dspmem_base + dspmem_size))
+#define is_dspbyte_internal_mem(db)    ((db) < dspmem_size)
+#define is_dspword_internal_mem(dw)    (((dw) << 1) < dspmem_size)
+
+#ifdef CONFIG_ARCH_OMAP1
+/*
+ * MPUI byteswap/wordswap on/off
+ *   default setting: wordswap = all, byteswap = APIMEM only
+ */
+#define mpui_wordswap_on() \
+       omap_set_bits_regl(MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL_WORDSWAP_MASK, \
+                          MPUI_CTRL)
+
+#define mpui_wordswap_off() \
+       omap_set_bits_regl(MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL_WORDSWAP_MASK, \
+                          MPUI_CTRL)
+
+#define mpui_byteswap_on() \
+       omap_set_bits_regl(MPUI_CTRL_BYTESWAP_API, MPUI_CTRL_BYTESWAP_MASK, \
+                          MPUI_CTRL)
+
+#define mpui_byteswap_off() \
+       omap_set_bits_regl(MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL_BYTESWAP_MASK, \
+                          MPUI_CTRL)
+
+/*
+ * TC wordswap on / off
+ */
+#define tc_wordswap() \
+       do { \
+               omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
+                           TC_ENDIANISM); \
+       } while(0)
+
+#define tc_noswap()    omap_clr_bit_regl(TC_ENDIANISM_EN, TC_ENDIANISM)
+
+/*
+ * enable priority registers, EMIF, MPUI control logic
+ */
+#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#define __dsp_disable()        omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1)
+#define __dsp_run()    omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
+#define __dsp_reset()  omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP2
+/*
+ * PRCM / IPI control logic
+ *
+ * REVISIT: these macros should probably be static inline functions
+ */
+#define __dsp_core_enable() \
+       do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+            & ~OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_core_disable() \
+       do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+            | OMAP24XX_RST1_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_enable() \
+       do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+            & ~OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#define __dsp_per_disable() \
+       do { prm_write_mod_reg(prm_read_mod_reg(OMAP24XX_DSP_MOD, RM_RSTCTRL) \
+            | OMAP24XX_RST2_DSP, OMAP24XX_DSP_MOD, RM_RSTCTRL); } while (0)
+#endif /* CONFIG_ARCH_OMAP2 */
+
+#if defined(CONFIG_ARCH_OMAP1)
+extern struct clk *dsp_ck_handle;
+extern struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+extern struct clk *dsp_fck_handle;
+extern struct clk *dsp_ick_handle;
+#endif
+extern dsp_long_t dspmem_base, dspmem_size,
+                 daram_base, daram_size,
+                 saram_base, saram_size;
+
+enum cpustat_e {
+       CPUSTAT_RESET = 0,
+#ifdef CONFIG_ARCH_OMAP1
+       CPUSTAT_GBL_IDLE,
+       CPUSTAT_CPU_IDLE,
+#endif
+       CPUSTAT_RUN,
+       CPUSTAT_MAX
+};
+
+int dsp_set_rstvect(dsp_long_t adr);
+dsp_long_t dsp_get_rstvect(void);
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size);
+void dsp_reset_idle_boot_base(void);
+void dsp_cpustat_request(enum cpustat_e req);
+enum cpustat_e dsp_cpustat_get_stat(void);
+u16 dsp_cpustat_get_icrmask(void);
+void dsp_cpustat_set_icrmask(u16 mask);
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
+void dsp_unregister_mem_cb(void);
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define command_dvfs_stop(m) (0)
+#define command_dvfs_start(m) (0)
+#elif defined(CONFIG_ARCH_OMAP2)
+#define command_dvfs_stop(m) \
+       (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_STOP))
+#define command_dvfs_start(m) \
+       (((m)->cmd_l == KFUNC_POWER) && ((m)->data == DVFS_START))
+#endif
+
+extern struct omap_dsp *omap_dsp;
+
+extern int dsp_late_init(void);
+
+#endif /* __PLAT_OMAP_DSP_DSP_H */
diff --git a/drivers/dsp/dspgateway/dsp_common.c b/drivers/dsp/dspgateway/dsp_common.c
new file mode 100644 (file)
index 0000000..9dffda2
--- /dev/null
@@ -0,0 +1,639 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <asm/irq.h>
+#include <mach/dsp_common.h>
+#include "dsp.h"
+
+#ifdef CONFIG_ARCH_OMAP1
+#include <mach/tc.h>
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1)
+#define dsp_boot_config(mode)  omap_writew((mode), MPUI_DSP_BOOT_CONFIG)
+#endif
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+#define dsp_boot_config(mode)  writel((mode), DSP_IPI_DSPBOOTCONFIG)
+#endif
+
+struct omap_dsp *omap_dsp;
+
+#if defined(CONFIG_ARCH_OMAP1)
+struct clk *dsp_ck_handle;
+struct clk *api_ck_handle;
+#elif defined(CONFIG_ARCH_OMAP2)
+struct clk *dsp_fck_handle;
+struct clk *dsp_ick_handle;
+#endif
+dsp_long_t dspmem_base, dspmem_size,
+          daram_base, daram_size,
+          saram_base, saram_size;
+
+static struct cpustat {
+       struct mutex lock;
+       enum cpustat_e stat;
+       enum cpustat_e req;
+       u16 icrmask;
+#ifdef CONFIG_ARCH_OMAP1
+       struct {
+               int mpui;
+               int mem;
+               int mem_delayed;
+       } usecount;
+       int (*mem_req_cb)(void);
+       void (*mem_rel_cb)(void);
+#endif
+} cpustat = {
+       .stat = CPUSTAT_RESET,
+       .icrmask = 0xffff,
+};
+
+int dsp_set_rstvect(dsp_long_t adr)
+{
+       unsigned long *dst_adr;
+
+       if (adr >= DSPSPACE_SIZE)
+               return -EINVAL;
+
+       dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+       /* word swap */
+       *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16);
+       /* fill 8 bytes! */
+       *(dst_adr + 1) = 0;
+       /* direct boot */
+       dsp_boot_config(DSP_BOOT_CONFIG_DIRECT);
+
+       return 0;
+}
+
+dsp_long_t dsp_get_rstvect(void)
+{
+       unsigned long *dst_adr;
+
+       dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT);
+       return ((*dst_adr & 0xffff) << 16) | (*dst_adr >> 16);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+static void simple_load_code(unsigned char *src_c, u16 *dst, int len)
+{
+       int i;
+       u16 *src = (u16 *)src_c;
+       int len_w;
+
+       /* len must be multiple of 2. */
+       if (len & 1)
+               BUG();
+
+       len_w = len / 2;
+       for (i = 0; i < len_w; i++) {
+               /* byte swap copy */
+               *dst = ((*src & 0x00ff) << 8) |
+                      ((*src & 0xff00) >> 8);
+               src++;
+               dst++;
+       }
+}
+
+/* program size must be multiple of 2 */
+#define GBL_IDLE_TEXT_SIZE     52
+#define GBL_IDLE_TEXT_INIT { \
+       /* SAM */ \
+       0x3c, 0x4a,                     /* 0x3c4a:     MOV 0x4, AR2 */ \
+       0xf4, 0x41, 0xfc, 0xff,         /* 0xf441fcff: AND 0xfcff, *AR2 */ \
+       /* disable WDT */ \
+       0x76, 0x34, 0x04, 0xb8,         /* 0x763404b8: MOV 0x3404, AR3 */ \
+       0xfb, 0x61, 0x00, 0xf5,         /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       0xfb, 0x61, 0x00, 0xa0,         /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       /* *IER0 = 0, *IER1 = 0 */ \
+       0x3c, 0x0b,                     /* 0x3c0b:     MOV 0x0, AR3 */ \
+       0xe6, 0x61, 0x00,               /* 0xe66100:   MOV 0, *AR3 */ \
+       0x76, 0x00, 0x45, 0xb8,         /* 0x76004508: MOV 0x45, AR3 */ \
+       0xe6, 0x61, 0x00,               /* 0xe66100:   MOV 0, *AR3 */ \
+       /* *ICR = 0xffff */ \
+       0x3c, 0x1b,                     /* 0x3c1b:     MOV 0x1, AR3 */ \
+       0xfb, 0x61, 0xff, 0xff,         /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       /* HOM */ \
+       0xf5, 0x41, 0x03, 0x00,         /* 0xf5410300: OR 0x0300, *AR2 */ \
+       /* idle and loop forever */ \
+       0x7a, 0x00, 0x00, 0x0c,         /* 0x7a00000c: IDLE */ \
+       0x4a, 0x7a,                     /* 0x4a7a:     B -6 (infinite loop) */ \
+       0x20, 0x20, 0x20,               /* 0x20:       NOP */ \
+}
+
+/* program size must be multiple of 2 */
+#define CPU_IDLE_TEXT_SIZE     48
+#define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
+       /* SAM */ \
+       0x3c, 0x4b,                     /* 0x3c4b:     MOV 0x4, AR3 */ \
+       0xf4, 0x61, 0xfc, 0xff,         /* 0xf461fcff: AND 0xfcff, *AR3 */ \
+       /* disable WDT */ \
+       0x76, 0x34, 0x04, 0xb8,         /* 0x763404b8: MOV 0x3404, AR3 */ \
+       0xfb, 0x61, 0x00, 0xf5,         /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       0xfb, 0x61, 0x00, 0xa0,         /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       /* *IER0 = 0, *IER1 = 0 */ \
+       0x3c, 0x0b,                     /* 0x3c0b:     MOV 0x0, AR3 */ \
+       0xe6, 0x61, 0x00,               /* 0xe66100:   MOV 0, *AR3 */ \
+       0x76, 0x00, 0x45, 0xb8,         /* 0x76004508: MOV 0x45, AR3 */ \
+       0xe6, 0x61, 0x00,               /* 0xe66100:   MOV 0, *AR3 */ \
+       /* set ICR = icr */ \
+       0x3c, 0x1b,                     /* 0x3c1b:     MOV AR3 0x1 */ \
+       0xfb, 0x61, (icrh), (icrl),     /* 0xfb61****: MOV *AR3, icr */ \
+       0x9a,                           /* 0x9a:       PORT */ \
+       /* idle and loop forever */ \
+       0x7a, 0x00, 0x00, 0x0c,         /* 0x7a00000c: IDLE */ \
+       0x4a, 0x7a,                     /* 0x4a7a:     B -6 (infinite loop) */ \
+       0x20, 0x20, 0x20                /* 0x20: nop */ \
+}
+
+/*
+ * idle_boot base:
+ * Initialized with DSP_BOOT_ADR_MPUI (=0x010000).
+ * This value is used before DSP Gateway driver is initialized.
+ * DSP Gateway driver will overwrite this value with other value,
+ * to avoid confliction with the user program.
+ */
+static dsp_long_t idle_boot_base = DSP_BOOT_ADR_MPUI;
+
+static void dsp_gbl_idle(void)
+{
+       unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
+
+       __dsp_reset();
+       clk_enable(api_ck_handle);
+
+#if 0
+       dsp_boot_config(DSP_BOOT_CONFIG_IDLE);
+#endif
+       simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+                        GBL_IDLE_TEXT_SIZE);
+       if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+               dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+       else
+               dsp_set_rstvect(idle_boot_base);
+
+       __dsp_run();
+       udelay(100);    /* to make things stable */
+       clk_disable(api_ck_handle);
+}
+
+static void dsp_cpu_idle(void)
+{
+       u16 icr_tmp;
+       unsigned char icrh, icrl;
+
+       __dsp_reset();
+       clk_enable(api_ck_handle);
+
+       /*
+        * icr settings:
+        * DMA should not sleep for DARAM/SARAM access
+        * DPLL should not sleep while any other domain is active
+        */
+       icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA | DSPREG_ICR_DPLL);
+       icrh = icr_tmp >> 8;
+       icrl = icr_tmp & 0xff;
+       {
+               unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
+               simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
+                                CPU_IDLE_TEXT_SIZE);
+       }
+       if (idle_boot_base == DSP_BOOT_ADR_MPUI)
+               dsp_boot_config(DSP_BOOT_CONFIG_MPUI);
+       else
+               dsp_set_rstvect(idle_boot_base);
+       __dsp_run();
+       udelay(100);    /* to make things stable */
+       clk_disable(api_ck_handle);
+}
+
+void dsp_set_idle_boot_base(dsp_long_t adr, size_t size)
+{
+       if (adr == idle_boot_base)
+               return;
+       idle_boot_base = adr;
+       if ((size < GBL_IDLE_TEXT_SIZE) ||
+           (size < CPU_IDLE_TEXT_SIZE)) {
+               printk(KERN_ERR
+                      "omapdsp: size for idle program is not enough!\n");
+               BUG();
+       }
+
+       /* restart idle program with new base address */
+       if (cpustat.stat == CPUSTAT_GBL_IDLE)
+               dsp_gbl_idle();
+       if (cpustat.stat == CPUSTAT_CPU_IDLE)
+               dsp_cpu_idle();
+}
+
+void dsp_reset_idle_boot_base(void)
+{
+       idle_boot_base = DSP_BOOT_ADR_MPUI;
+}
+#else
+void dsp_reset_idle_boot_base(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+static int init_done;
+
+static int omap_dsp_init(void)
+{
+       mutex_init(&cpustat.lock);
+
+       dspmem_size = 0;
+#ifdef CONFIG_ARCH_OMAP15XX
+       if (cpu_is_omap15xx()) {
+               dspmem_base = OMAP1510_DSP_BASE;
+               dspmem_size = OMAP1510_DSP_SIZE;
+               daram_base = OMAP1510_DARAM_BASE;
+               daram_size = OMAP1510_DARAM_SIZE;
+               saram_base = OMAP1510_SARAM_BASE;
+               saram_size = OMAP1510_SARAM_SIZE;
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+       if (cpu_is_omap16xx()) {
+               dspmem_base = OMAP16XX_DSP_BASE;
+               dspmem_size = OMAP16XX_DSP_SIZE;
+               daram_base = OMAP16XX_DARAM_BASE;
+               daram_size = OMAP16XX_DARAM_SIZE;
+               saram_base = OMAP16XX_SARAM_BASE;
+               saram_size = OMAP16XX_SARAM_SIZE;
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+       if (cpu_is_omap24xx()) {
+               dspmem_base = DSP_MEM_24XX_VIRT;
+               dspmem_size = DSP_MEM_24XX_SIZE;
+               daram_base = OMAP24XX_DARAM_BASE;
+               daram_size = OMAP24XX_DARAM_SIZE;
+               saram_base = OMAP24XX_SARAM_BASE;
+               saram_size = OMAP24XX_SARAM_SIZE;
+       }
+#endif
+#ifdef CONFIG_ARCH_OMAP34XX
+       /* To be Revisited for 3430 */
+       if (cpu_is_omap34xx()) {
+               return -ENODEV;
+       }
+#endif
+       if (dspmem_size == 0) {
+               printk(KERN_ERR "omapdsp: unsupported omap architecture.\n");
+               return -ENODEV;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1)
+       dsp_ck_handle = clk_get(NULL, "dsp_ck");
+       if (IS_ERR(dsp_ck_handle)) {
+               printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n");
+               return PTR_ERR(dsp_ck_handle);
+       }
+
+       api_ck_handle = clk_get(NULL, "api_ck");
+       if (IS_ERR(api_ck_handle)) {
+               printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n");
+               if (dsp_ck_handle != NULL)
+                       clk_put(dsp_ck_handle);
+               return PTR_ERR(api_ck_handle);
+       }
+
+       /* This is needed for McBSP init, released in late_initcall */
+       clk_enable(api_ck_handle);
+
+       __dsp_enable();
+       mpui_byteswap_off();
+       mpui_wordswap_on();
+       tc_wordswap();
+#elif defined(CONFIG_ARCH_OMAP2)
+       dsp_fck_handle = clk_get(NULL, "dsp_fck");
+       if (IS_ERR(dsp_fck_handle)) {
+               printk(KERN_ERR "omapdsp: could not acquire dsp_fck handle.\n");
+               return PTR_ERR(dsp_fck_handle);
+       }
+
+# if defined(CONFIG_ARCH_OMAP2420)
+       dsp_ick_handle = clk_get(NULL, "dsp_ick");
+# elif defined(CONFIG_ARCH_OMAP2430)
+       /*
+        * 2430 has no separate switch for DSP ICLK, but this at least
+        * involves the minimal change to the rest of the code.
+        */
+       dsp_ick_handle = clk_get(NULL, "iva2_1_ick");
+# endif
+       if (IS_ERR(dsp_ick_handle)) {
+               printk(KERN_ERR "omapdsp: could not acquire dsp_ick handle.\n");
+               if (dsp_fck_handle != NULL)
+                       clk_put(dsp_fck_handle);
+               return PTR_ERR(dsp_ick_handle);
+       }
+#endif
+
+       init_done = 1;
+       pr_info("omap_dsp_init() done\n");
+       return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static int __dsp_late_init(void)
+{
+       clk_disable(api_ck_handle);
+       return 0;
+}
+late_initcall(__dsp_late_init);
+#endif
+
+static void dsp_cpustat_update(void)
+{
+       if (!init_done)
+               omap_dsp_init();
+
+       if (cpustat.req == CPUSTAT_RUN) {
+               if (cpustat.stat < CPUSTAT_RUN) {
+#if defined(CONFIG_ARCH_OMAP1)
+                       __dsp_reset();
+                       clk_enable(api_ck_handle);
+                       udelay(10);
+                       __dsp_run();
+#elif defined(CONFIG_ARCH_OMAP2)
+                       __dsp_core_disable();
+                       udelay(10);
+                       __dsp_core_enable();
+#endif
+                       cpustat.stat = CPUSTAT_RUN;
+               }
+               return;
+       }
+
+       /* cpustat.req < CPUSTAT_RUN */
+
+       if (cpustat.stat == CPUSTAT_RUN) {
+#ifdef CONFIG_ARCH_OMAP1
+               clk_disable(api_ck_handle);
+#endif
+       }
+
+#ifdef CONFIG_ARCH_OMAP1
+       /*
+        * (1) when ARM wants DARAM access, MPUI should be SAM and
+        *     DSP needs to be on.
+        * (2) if any bits of icr is masked, we can not enter global idle.
+        */
+       if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
+           (cpustat.usecount.mem > 0) ||
+           (cpustat.usecount.mem_delayed > 0) ||
+           ((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
+               if (cpustat.stat != CPUSTAT_CPU_IDLE) {
+                       dsp_cpu_idle();
+                       cpustat.stat = CPUSTAT_CPU_IDLE;
+               }
+               return;
+       }
+
+       /*
+        * when ARM only needs MPUI access, MPUI can be HOM and
+        * DSP can be idling.
+        */
+       if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
+           (cpustat.usecount.mpui > 0)) {
+               if (cpustat.stat != CPUSTAT_GBL_IDLE) {
+                       dsp_gbl_idle();
+                       cpustat.stat = CPUSTAT_GBL_IDLE;
+               }
+               return;
+       }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+       /*
+        * no user, no request
+        */
+       if (cpustat.stat != CPUSTAT_RESET) {
+#if defined(CONFIG_ARCH_OMAP1)
+               __dsp_reset();
+#elif defined(CONFIG_ARCH_OMAP2)
+               __dsp_core_disable();
+#endif
+               cpustat.stat = CPUSTAT_RESET;
+       }
+}
+
+void dsp_cpustat_request(enum cpustat_e req)
+{
+       mutex_lock(&cpustat.lock);
+       cpustat.req = req;
+       dsp_cpustat_update();
+       mutex_unlock(&cpustat.lock);
+}
+
+enum cpustat_e dsp_cpustat_get_stat(void)
+{
+       return cpustat.stat;
+}
+
+u16 dsp_cpustat_get_icrmask(void)
+{
+       return cpustat.icrmask;
+}
+
+void dsp_cpustat_set_icrmask(u16 mask)
+{
+       mutex_lock(&cpustat.lock);
+       cpustat.icrmask = mask;
+       dsp_cpustat_update();
+       mutex_unlock(&cpustat.lock);
+}
+
+#ifdef CONFIG_ARCH_OMAP1
+void omap_dsp_request_mpui(void)
+{
+       mutex_lock(&cpustat.lock);
+       if (cpustat.usecount.mpui++ == 0)
+               dsp_cpustat_update();
+       mutex_unlock(&cpustat.lock);
+}
+
+void omap_dsp_release_mpui(void)
+{
+       mutex_lock(&cpustat.lock);
+       if (cpustat.usecount.mpui-- == 0) {
+               printk(KERN_ERR
+                      "omapdsp: unbalanced mpui request/release detected.\n"
+                      "         cpustat.usecount.mpui is going to be "
+                      "less than zero! ... fixed to be zero.\n");
+               cpustat.usecount.mpui = 0;
+       }
+       if (cpustat.usecount.mpui == 0)
+               dsp_cpustat_update();
+       mutex_unlock(&cpustat.lock);
+}
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
+int omap_dsp_request_mem(void)
+{
+       int ret = 0;
+
+       mutex_lock(&cpustat.lock);
+       if ((cpustat.usecount.mem++ == 0) &&
+           (cpustat.usecount.mem_delayed == 0)) {
+               if (cpustat.mem_req_cb) {
+                       if ((ret = cpustat.mem_req_cb()) < 0) {
+                               cpustat.usecount.mem--;
+                               goto out;
+                       }
+               }
+               dsp_cpustat_update();
+       }
+out:
+       mutex_unlock(&cpustat.lock);
+
+       return ret;
+}
+
+/*
+ * release_mem will be delayed.
+ */
+static void do_release_mem(struct work_struct *dummy)
+{
+       mutex_lock(&cpustat.lock);
+       cpustat.usecount.mem_delayed = 0;
+       if (cpustat.usecount.mem == 0) {
+               dsp_cpustat_update();
+               if (cpustat.mem_rel_cb)
+                       cpustat.mem_rel_cb();
+       }
+       mutex_unlock(&cpustat.lock);
+}
+
+static DECLARE_DELAYED_WORK(mem_rel_work, do_release_mem);
+
+int omap_dsp_release_mem(void)
+{
+       mutex_lock(&cpustat.lock);
+
+       /* cancel previous release work */
+       cancel_delayed_work(&mem_rel_work);
+       cpustat.usecount.mem_delayed = 0;
+
+       if (cpustat.usecount.mem-- == 0) {
+               printk(KERN_ERR
+                      "omapdsp: unbalanced memory request/release detected.\n"
+                      "         cpustat.usecount.mem is going to be "
+                      "less than zero! ... fixed to be zero.\n");
+               cpustat.usecount.mem = 0;
+       }
+       if (cpustat.usecount.mem == 0) {
+               cpustat.usecount.mem_delayed = 1;
+               schedule_delayed_work(&mem_rel_work, HZ);
+       }
+
+       mutex_unlock(&cpustat.lock);
+
+       return 0;
+}
+#endif
+
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
+{
+       mutex_lock(&cpustat.lock);
+
+       cpustat.mem_req_cb = req_cb;
+       cpustat.mem_rel_cb = rel_cb;
+
+       /*
+        * This function must be called while mem is enabled!
+        */
+       BUG_ON(cpustat.usecount.mem == 0);
+
+       mutex_unlock(&cpustat.lock);
+}
+
+void dsp_unregister_mem_cb(void)
+{
+       mutex_lock(&cpustat.lock);
+       cpustat.mem_req_cb = NULL;
+       cpustat.mem_rel_cb = NULL;
+       mutex_unlock(&cpustat.lock);
+}
+#else
+void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void)) { }
+void dsp_unregister_mem_cb(void) { }
+#endif /* CONFIG_ARCH_OMAP1 */
+
+arch_initcall(omap_dsp_init);
+
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(omap_dsp_request_mpui);
+EXPORT_SYMBOL(omap_dsp_release_mpui);
+#if defined(CONFIG_ARCH_OMAP1) && defined(CONFIG_OMAP_MMU_FWK)
+EXPORT_SYMBOL(omap_dsp_request_mem);
+EXPORT_SYMBOL(omap_dsp_release_mem);
+#endif
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_OMAP_DSP_MODULE
+#if defined(CONFIG_ARCH_OMAP1)
+EXPORT_SYMBOL(dsp_ck_handle);
+EXPORT_SYMBOL(api_ck_handle);
+#elif defined(CONFIG_ARCH_OMAP2)
+EXPORT_SYMBOL(dsp_fck_handle);
+EXPORT_SYMBOL(dsp_ick_handle);
+#endif
+EXPORT_SYMBOL(omap_dsp);
+EXPORT_SYMBOL(dspmem_base);
+EXPORT_SYMBOL(dspmem_size);
+EXPORT_SYMBOL(daram_base);
+EXPORT_SYMBOL(daram_size);
+EXPORT_SYMBOL(saram_base);
+EXPORT_SYMBOL(saram_size);
+EXPORT_SYMBOL(dsp_set_rstvect);
+EXPORT_SYMBOL(dsp_get_rstvect);
+#ifdef CONFIG_ARCH_OMAP1
+EXPORT_SYMBOL(dsp_set_idle_boot_base);
+EXPORT_SYMBOL(dsp_reset_idle_boot_base);
+#endif /* CONFIG_ARCH_OMAP1 */
+EXPORT_SYMBOL(dsp_cpustat_request);
+EXPORT_SYMBOL(dsp_cpustat_get_stat);
+EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
+EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
+EXPORT_SYMBOL(dsp_register_mem_cb);
+EXPORT_SYMBOL(dsp_unregister_mem_cb);
+
+EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
+EXPORT_SYMBOL(cpu_architecture);
+EXPORT_SYMBOL(pmd_clear_bad);
+#endif
diff --git a/drivers/dsp/dspgateway/dsp_core.c b/drivers/dsp/dspgateway/dsp_core.c
new file mode 100644 (file)
index 0000000..f2368fb
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/delay.h>
+#include <mach/mailbox.h>
+#include <mach/dsp.h>
+#include <mach/dsp_common.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+MODULE_AUTHOR("Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>");
+MODULE_DESCRIPTION("OMAP DSP driver module");
+MODULE_LICENSE("GPL");
+
+static struct sync_seq *mbseq;
+static u16 mbseq_expect_tmp;
+static u16 *mbseq_expect = &mbseq_expect_tmp;
+
+extern int dsp_mem_late_init(void);
+
+/*
+ * mailbox commands
+ */
+extern void mbox_wdsnd(struct mbcmd *mb);
+extern void mbox_wdreq(struct mbcmd *mb);
+extern void mbox_bksnd(struct mbcmd *mb);
+extern void mbox_bkreq(struct mbcmd *mb);
+extern void mbox_bkyld(struct mbcmd *mb);
+extern void mbox_bksndp(struct mbcmd *mb);
+extern void mbox_bkreqp(struct mbcmd *mb);
+extern void mbox_tctl(struct mbcmd *mb);
+extern void mbox_poll(struct mbcmd *mb);
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+extern void mbox_wdt(struct mbcmd *mb);
+#endif
+extern void mbox_suspend(struct mbcmd *mb);
+static void mbox_kfunc(struct mbcmd *mb);
+extern void mbox_tcfg(struct mbcmd *mb);
+extern void mbox_tadd(struct mbcmd *mb);
+extern void mbox_tdel(struct mbcmd *mb);
+extern void mbox_dspcfg(struct mbcmd *mb);
+extern void mbox_regrw(struct mbcmd *mb);
+extern void mbox_getvar(struct mbcmd *mb);
+extern void mbox_err(struct mbcmd *mb);
+extern void mbox_dbg(struct mbcmd *mb);
+
+static const struct cmdinfo
+       cif_wdsnd    = { "WDSND",    CMD_L_TYPE_TID,    mbox_wdsnd   },
+       cif_wdreq    = { "WDREQ",    CMD_L_TYPE_TID,    mbox_wdreq   },
+       cif_bksnd    = { "BKSND",    CMD_L_TYPE_TID,    mbox_bksnd   },
+       cif_bkreq    = { "BKREQ",    CMD_L_TYPE_TID,    mbox_bkreq   },
+       cif_bkyld    = { "BKYLD",    CMD_L_TYPE_NULL,   mbox_bkyld   },
+       cif_bksndp   = { "BKSNDP",   CMD_L_TYPE_TID,    mbox_bksndp  },
+       cif_bkreqp   = { "BKREQP",   CMD_L_TYPE_TID,    mbox_bkreqp  },
+       cif_tctl     = { "TCTL",     CMD_L_TYPE_TID,    mbox_tctl    },
+       cif_poll     = { "POLL",     CMD_L_TYPE_NULL,   mbox_poll    },
+#ifdef OLD_BINARY_SUPPORT
+       /* v3.3 obsolete */
+       cif_wdt      = { "WDT",      CMD_L_TYPE_NULL,   mbox_wdt     },
+#endif
+       cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL        },
+       cif_pm       = { "PM",       CMD_L_TYPE_SUBCMD, NULL        },
+       cif_suspend  = { "SUSPEND",  CMD_L_TYPE_NULL,   mbox_suspend },
+       cif_kfunc    = { "KFUNC",    CMD_L_TYPE_SUBCMD, mbox_kfunc   },
+       cif_tcfg     = { "TCFG",     CMD_L_TYPE_TID,    mbox_tcfg    },
+       cif_tadd     = { "TADD",     CMD_L_TYPE_TID,    mbox_tadd    },
+       cif_tdel     = { "TDEL",     CMD_L_TYPE_TID,    mbox_tdel    },
+       cif_tstop    = { "TSTOP",    CMD_L_TYPE_TID,    NULL        },
+       cif_dspcfg   = { "DSPCFG",   CMD_L_TYPE_SUBCMD, mbox_dspcfg  },
+       cif_regrw    = { "REGRW",    CMD_L_TYPE_SUBCMD, mbox_regrw   },
+       cif_getvar   = { "GETVAR",   CMD_L_TYPE_SUBCMD, mbox_getvar  },
+       cif_setvar   = { "SETVAR",   CMD_L_TYPE_SUBCMD, NULL        },
+       cif_err      = { "ERR",      CMD_L_TYPE_SUBCMD, mbox_err     },
+       cif_dbg      = { "DBG",      CMD_L_TYPE_NULL,   mbox_dbg     };
+
+#define MBOX_CMD_MAX   0x80
+const struct cmdinfo *cmdinfo[MBOX_CMD_MAX] = {
+       [MBOX_CMD_DSP_WDSND]    = &cif_wdsnd,
+       [MBOX_CMD_DSP_WDREQ]    = &cif_wdreq,
+       [MBOX_CMD_DSP_BKSND]    = &cif_bksnd,
+       [MBOX_CMD_DSP_BKREQ]    = &cif_bkreq,
+       [MBOX_CMD_DSP_BKYLD]    = &cif_bkyld,
+       [MBOX_CMD_DSP_BKSNDP]   = &cif_bksndp,
+       [MBOX_CMD_DSP_BKREQP]   = &cif_bkreqp,
+       [MBOX_CMD_DSP_TCTL]     = &cif_tctl,
+       [MBOX_CMD_DSP_POLL]     = &cif_poll,
+#ifdef OLD_BINARY_SUPPORT
+       [MBOX_CMD_DSP_WDT]      = &cif_wdt, /* v3.3 obsolete */
+#endif
+       [MBOX_CMD_DSP_RUNLEVEL] = &cif_runlevel,
+       [MBOX_CMD_DSP_PM]       = &cif_pm,
+       [MBOX_CMD_DSP_SUSPEND]  = &cif_suspend,
+       [MBOX_CMD_DSP_KFUNC]    = &cif_kfunc,
+       [MBOX_CMD_DSP_TCFG]     = &cif_tcfg,
+       [MBOX_CMD_DSP_TADD]     = &cif_tadd,
+       [MBOX_CMD_DSP_TDEL]     = &cif_tdel,
+       [MBOX_CMD_DSP_TSTOP]    = &cif_tstop,
+       [MBOX_CMD_DSP_DSPCFG]   = &cif_dspcfg,
+       [MBOX_CMD_DSP_REGRW]    = &cif_regrw,
+       [MBOX_CMD_DSP_GETVAR]   = &cif_getvar,
+       [MBOX_CMD_DSP_SETVAR]   = &cif_setvar,
+       [MBOX_CMD_DSP_ERR]      = &cif_err,
+       [MBOX_CMD_DSP_DBG]      = &cif_dbg,
+};
+
+#define list_for_each_entry_safe_natural(p,n,h,m) \
+                       list_for_each_entry_safe(p,n,h,m)
+#define __BUILD_KFUNC(fn, dir)                                                 \
+static int __dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)\
+{                                                                              \
+       struct dsp_kfunc_device *p, *tmp;                                       \
+       int ret, fail = 0;                                                      \
+                                                                               \
+       list_for_each_entry_safe_##dir(p, tmp, dsp->kdev_list, entry) {         \
+               if (type && (p->type != type))                                  \
+                       continue;                                               \
+               if (p->fn == NULL)                                              \
+                       continue;                                               \
+               ret = p->fn(p, stage);                                          \
+               if (ret) {                                                      \
+                       printk(KERN_ERR "%s %s failed\n", #fn, p->name);        \
+                       fail++;                                                 \
+               }                                                               \
+       }                                                                       \
+       return fail;                                                            \
+}
+#define BUILD_KFUNC(fn, dir)                                           \
+__BUILD_KFUNC(fn, dir)                                                 \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp)       \
+{                                                                      \
+       return __dsp_kfunc_##fn##_devices(dsp, 0, 0);                   \
+}
+#define BUILD_KFUNC_CTL(fn, dir)                                                       \
+__BUILD_KFUNC(fn, dir)                                                                 \
+static inline int dsp_kfunc_##fn##_devices(struct omap_dsp *dsp, int type, int stage)  \
+{                                                                                      \
+       return __dsp_kfunc_##fn##_devices(dsp, type, stage);                            \
+}
+
+BUILD_KFUNC(probe, natural)
+BUILD_KFUNC(remove, reverse)
+BUILD_KFUNC_CTL(enable, natural)
+BUILD_KFUNC_CTL(disable, reverse)
+
+int sync_with_dsp(u16 *adr, u16 val, int try_cnt)
+{
+       int try;
+
+       if (*(volatile u16 *)adr == val)
+               return 0;
+
+       for (try = 0; try < try_cnt; try++) {
+               udelay(1);
+               if (*(volatile u16 *)adr == val) {
+                       /* success! */
+                       pr_info("omapdsp: sync_with_dsp(): try = %d\n", try);
+                       return 0;
+               }
+       }
+
+       /* fail! */
+       return -1;
+}
+
+static int mbcmd_sender_prepare(void *data)
+{
+       struct mb_exarg *arg = data;
+       int i, ret = 0;
+       /*
+        * even if ipbuf_sys_ad is in DSP internal memory,
+        * dsp_mem_enable() never cause to call PM mailbox command
+        * because in that case DSP memory should be always enabled.
+        * (see ipbuf_sys_hold_mem_active in ipbuf.c)
+        *
+        * Therefore, we can call this function here safely.
+        */
+       dsp_mem_enable(ipbuf_sys_ad);
+       if (sync_with_dsp(&ipbuf_sys_ad->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       for (i = 0; i < arg->argc; i++) {
+               ipbuf_sys_ad->d[i] = arg->argv[i];
+       }
+       ipbuf_sys_ad->s = arg->tid;
+ out:
+       dsp_mem_disable(ipbuf_sys_ad);
+       return ret;
+}
+
+/*
+ * __dsp_mbcmd_send_exarg(): mailbox dispatcher
+ */
+int __dsp_mbcmd_send_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                          int recovery_flag)
+{
+       int ret = 0;
+
+       if (unlikely(omap_dsp->enabled == 0)) {
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 1;
+       }
+
+       /*
+        * while MMU fault is set,
+        * only recovery command can be executed
+        */
+       if (dsp_err_isset(ERRCODE_MMU) && !recovery_flag) {
+               printk(KERN_ERR
+                      "mbox: mmu interrupt is set. %s is aborting.\n",
+                      cmd_name(*mb));
+               goto out;
+       }
+
+       ret = omap_mbox_msg_send(omap_dsp->mbox,
+                                *(mbox_msg_t *)mb, (void*)arg);
+       if (ret)
+               goto out;
+
+       if (mbseq)
+               mbseq->ad_arm++;
+
+       mblog_add(mb, DIR_A2D);
+ out:
+       return ret;
+}
+
+int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
+                                 wait_queue_head_t *q)
+{
+       int ret;
+
+       DEFINE_WAIT(wait);
+       prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+       ret = dsp_mbcmd_send_exarg(mb, arg);
+       if (ret < 0)
+               goto out;
+       schedule_timeout(DSP_TIMEOUT);
+ out:
+       finish_wait(q, &wait);
+       return ret;
+}
+
+/*
+ * mbcmd receiver
+ */
+static int mbcmd_receiver(void* msg)
+{
+       struct mbcmd *mb = (struct mbcmd *)&msg;
+
+       if (cmdinfo[mb->cmd_h] == NULL) {
+               printk(KERN_ERR
+                      "invalid message (%08x) for mbcmd_receiver().\n",
+                      (mbox_msg_t)msg);
+               return -1;
+       }
+
+       (*mbseq_expect)++;
+
+       mblog_add(mb, DIR_D2A);
+
+       /* call handler for the command */
+       if (cmdinfo[mb->cmd_h]->handler)
+               cmdinfo[mb->cmd_h]->handler(mb);
+       else
+               printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
+                      cmd_name(*mb));
+       return 0;
+}
+
+static int mbsync_hold_mem_active;
+
+void dsp_mbox_start(void)
+{
+       omap_mbox_init_seq(omap_dsp->mbox);
+       mbseq_expect_tmp = 0;
+}
+
+void dsp_mbox_stop(void)
+{
+       mbseq = NULL;
+       mbseq_expect = &mbseq_expect_tmp;
+}
+
+int dsp_mbox_config(void *p)
+{
+       unsigned long flags;
+
+       if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: mbseq is placed in DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n");
+               mbsync_hold_mem_active = 1;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       local_irq_save(flags);
+       mbseq = p;
+       mbseq->da_arm = mbseq_expect_tmp;
+       mbseq_expect = &mbseq->da_arm;
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static int __init dsp_mbox_init(void)
+{
+       omap_dsp->mbox = omap_mbox_get("dsp");
+       if (IS_ERR(omap_dsp->mbox)) {
+               printk(KERN_ERR "failed to get mailbox handler for DSP.\n");
+               return -ENODEV;
+       }
+
+       omap_dsp->mbox->rxq->callback = mbcmd_receiver;
+       omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
+
+       return 0;
+}
+
+static void dsp_mbox_exit(void)
+{
+       omap_dsp->mbox->txq->callback = NULL;
+       omap_dsp->mbox->rxq->callback = NULL;
+
+       omap_mbox_put(omap_dsp->mbox);
+
+       if (mbsync_hold_mem_active) {
+               dsp_mem_disable((void *)daram_base);
+               mbsync_hold_mem_active = 0;
+       }
+}
+
+/*
+ * kernel function dispatcher
+ */
+extern void mbox_fbctl_upd(void);
+extern void mbox_fbctl_disable(struct mbcmd *mb);
+
+static void mbox_kfunc_fbctl(struct mbcmd *mb)
+{
+       switch (mb->data) {
+       case FBCTL_UPD:
+               mbox_fbctl_upd();
+               break;
+       case FBCTL_DISABLE:
+               mbox_fbctl_disable(mb);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown FBCTL from DSP: 0x%04x\n", mb->data);
+       }
+}
+
+/*
+ * dspgw: KFUNC message handler
+ */
+static void mbox_kfunc_power(unsigned short data)
+{
+       int ret = -1;
+
+       switch (data) {
+       case DVFS_START: /* ACK from DSP */
+               /* TBD */
+               break;
+       case AUDIO_PWR_UP:
+               ret = dsp_kfunc_enable_devices(omap_dsp,
+                                              DSP_KFUNC_DEV_TYPE_AUDIO, 0);
+               if (ret == 0)
+                       ret++;
+               break;
+       case AUDIO_PWR_DOWN: /* == AUDIO_PWR_DOWN1 */
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 1);
+               break;
+       case AUDIO_PWR_DOWN2:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_AUDIO, 2);
+               break;
+       case DSP_PWR_DOWN:
+               ret = dsp_kfunc_disable_devices(omap_dsp,
+                                               DSP_KFUNC_DEV_TYPE_COMMON, 0);
+               if (ret == 0)
+                       omap_dsp->enabled = 0;
+               break;
+       default:
+               printk(KERN_ERR
+                      "mailbox: Unknown PWR from DSP: 0x%04x\n", data);
+               break;
+       }
+
+       if (unlikely(ret < 0)) {
+               printk(KERN_ERR "mailbox: PWR(0x%04x) failed\n", data);
+               return;
+       }
+
+       if (likely(ret == 0))
+               return;
+
+       mbcompose_send(KFUNC, KFUNC_POWER, data);
+}
+
+static void mbox_kfunc(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case KFUNC_FBCTL:
+               mbox_kfunc_fbctl(mb);
+               break;
+       case KFUNC_POWER:
+               mbox_kfunc_power(mb->data);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown KFUNC from DSP: 0x%02x\n", mb->cmd_l);
+       }
+}
+
+#if defined(CONFIG_ARCH_OMAP1)
+static inline void dsp_clk_enable(void) {}
+static inline void dsp_clk_disable(void) {}
+#elif defined(CONFIG_ARCH_OMAP2)
+static inline void dsp_clk_enable(void)
+{
+       clk_enable(dsp_fck_handle);
+       clk_enable(dsp_ick_handle);
+       __dsp_per_enable();
+}
+static inline void dsp_clk_disable(void)
+{
+       __dsp_per_disable();
+       clk_disable(dsp_ick_handle);
+       clk_disable(dsp_fck_handle);
+}
+#endif
+
+int dsp_late_init(void)
+{
+       int ret;
+
+       dsp_clk_enable();
+       ret = dsp_mem_late_init();
+       if (ret)
+               return ret;
+       ret = dsp_mbox_init();
+       if (ret)
+               goto fail_mbox;
+#ifdef CONFIG_ARCH_OMAP1
+       dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE);
+#endif
+       ret = dsp_kfunc_enable_devices(omap_dsp,
+                                      DSP_KFUNC_DEV_TYPE_COMMON, 0);
+       if (ret)
+               goto fail_kfunc;
+       omap_dsp->enabled = 1;
+
+       return 0;
+
+ fail_kfunc:
+       dsp_mbox_exit();
+ fail_mbox:
+       dsp_clk_disable();
+
+       return ret;
+}
+
+extern int  dsp_ctl_core_init(void);
+extern void dsp_ctl_core_exit(void);
+extern int dsp_ctl_init(void);
+extern void dsp_ctl_exit(void);
+extern int  dsp_mem_init(void);
+extern void dsp_mem_exit(void);
+extern void mblog_init(void);
+extern void mblog_exit(void);
+extern int  dsp_taskmod_init(void);
+extern void dsp_taskmod_exit(void);
+
+/*
+ * driver functions
+ */
+static int __init dsp_drv_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_dsp *info;
+       struct dsp_platform_data *pdata = pdev->dev.platform_data;
+
+       dev_info(&pdev->dev, "OMAP DSP driver initialization\n");
+
+       info = kzalloc(sizeof(struct omap_dsp), GFP_KERNEL);
+       if (unlikely(info == NULL)) {
+               dev_dbg(&pdev->dev, "no memory for info\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, info);
+       omap_dsp = info;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->kdev_list = &pdata->kdev_list;
+
+       ret = dsp_kfunc_probe_devices(info);
+       if (ret) {
+               ret = -ENXIO;
+               goto fail_kfunc;
+       }
+
+       ret = dsp_ctl_core_init();
+       if (ret)
+               goto fail_ctl_core;
+       ret = dsp_mem_init();
+       if (ret)
+               goto fail_mem;
+       ret = dsp_ctl_init();
+       if (unlikely(ret))
+               goto fail_ctl_init;
+       mblog_init();
+       ret = dsp_taskmod_init();
+       if (ret)
+               goto fail_taskmod;
+
+       return 0;
+
+ fail_taskmod:
+       mblog_exit();
+       dsp_ctl_exit();
+ fail_ctl_init:
+       dsp_mem_exit();
+ fail_mem:
+       dsp_ctl_core_exit();
+ fail_ctl_core:
+       dsp_kfunc_remove_devices(info);
+ fail_kfunc:
+       kfree(info);
+
+       return ret;
+}
+
+static int dsp_drv_remove(struct platform_device *pdev)
+{
+       struct omap_dsp *info = platform_get_drvdata(pdev);
+
+       dsp_cpustat_request(CPUSTAT_RESET);
+
+       dsp_cfgstat_request(CFGSTAT_CLEAN);
+       dsp_mbox_exit();
+       dsp_taskmod_exit();
+       mblog_exit();
+       dsp_ctl_exit();
+       dsp_mem_exit();
+
+       dsp_ctl_core_exit();
+
+#ifdef CONFIG_ARCH_OMAP2
+       __dsp_per_disable();
+       clk_disable(dsp_ick_handle);
+       clk_disable(dsp_fck_handle);
+#endif
+       dsp_kfunc_remove_devices(info);
+       kfree(info);
+
+       return 0;
+}
+
+#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP1)
+static int dsp_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       dsp_cfgstat_request(CFGSTAT_SUSPEND);
+
+       return 0;
+}
+
+static int dsp_drv_resume(struct platform_device *pdev)
+{
+       dsp_cfgstat_request(CFGSTAT_RESUME);
+
+       return 0;
+}
+#else
+#define dsp_drv_suspend                NULL
+#define dsp_drv_resume         NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver dsp_driver = {
+       .probe          = dsp_drv_probe,
+       .remove         = dsp_drv_remove,
+       .suspend        = dsp_drv_suspend,
+       .resume         = dsp_drv_resume,
+       .driver         = {
+               .name   = "dsp",
+       },
+};
+
+static int __init omap_dsp_mod_init(void)
+{
+       return platform_driver_register(&dsp_driver);
+}
+
+static void __exit omap_dsp_mod_exit(void)
+{
+       platform_driver_unregister(&dsp_driver);
+}
+
+/* module dependency: need mailbox module that have mbox_dsp_info */
+extern struct omap_mbox mbox_dsp_info;
+struct omap_mbox *mbox_dep = &mbox_dsp_info;
+
+module_init(omap_dsp_mod_init);
+module_exit(omap_dsp_mod_exit);
diff --git a/drivers/dsp/dspgateway/dsp_ctl.c b/drivers/dsp/dspgateway/dsp_ctl.c
new file mode 100644 (file)
index 0000000..712c3cf
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/ioctls.h>
+#include <mach/mailbox.h>
+#include <mach/dsp.h>
+#include "hardware_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+enum dsp_space_e {
+       SPACE_MEM,
+       SPACE_IO,
+};
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static enum fbstat_e {
+       FBSTAT_DISABLED = 0,
+       FBSTAT_ENABLED,
+       FBSTAT_MAX,
+} fbstat = FBSTAT_ENABLED;
+#endif
+
+static enum cfgstat_e cfgstat;
+int mbox_revision;
+static u8 n_stask;
+
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf);
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count);
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf);
+
+#define __ATTR_RW(_name, _mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_ifver     = __ATTR_RO(ifver);
+static struct device_attribute dev_attr_cpustat   = __ATTR_RO(cpustat);
+static struct device_attribute dev_attr_icrmask   = __ATTR_RW(icrmask, 0644);
+static struct device_attribute dev_attr_loadinfo  = __ATTR_RO(loadinfo);
+
+/*
+ * misc interactive mailbox command operations
+ */
+static struct misc_mb_wait_struct {
+       struct mutex lock;
+       wait_queue_head_t wait_q;
+       u8 cmd_h;
+       u8 cmd_l;
+       u16 *retvp;
+} misc_mb_wait = {
+       .lock = __MUTEX_INITIALIZER(misc_mb_wait.lock),
+       .wait_q = __WAIT_QUEUE_HEAD_INITIALIZER(misc_mb_wait.wait_q),
+};
+
+static int __misc_mbcompose_send_and_wait(u8 cmd_h, u8 cmd_l, u16 data,
+                                         u16 *retvp)
+{
+       struct mbcmd mb = MBCMD_INIT(cmd_h, cmd_l, data);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&misc_mb_wait.lock))
+               return -EINTR;
+
+       misc_mb_wait.cmd_h = mb.cmd_h;
+       misc_mb_wait.cmd_l = mb.cmd_l;
+       misc_mb_wait.retvp = retvp;
+       dsp_mbcmd_send_and_wait(&mb, &misc_mb_wait.wait_q);
+
+       if (misc_mb_wait.cmd_h != 0)
+               ret = -EINVAL;
+
+       mutex_unlock(&misc_mb_wait.lock);
+       return ret;
+}
+
+#define misc_mbcompose_send_and_wait(cmd_h, cmd_l, data, retvp) \
+               __misc_mbcompose_send_and_wait(MBOX_CMD_DSP_##cmd_h, (cmd_l), \
+                                              (data), (retvp));
+
+static int misc_mbcmd_response(struct mbcmd *mb, int argc, int match_cmd_l_flag)
+{
+       volatile u16 *buf;
+       int i;
+
+       /* if match_cmd_l_v flag is set, cmd_l needs to be matched as well. */
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != mb->cmd_h) ||
+           (match_cmd_l_flag && (misc_mb_wait.cmd_l != mb->cmd_l))) {
+               const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+               char cmdstr[32];
+
+               if (ci->cmd_l_type == CMD_L_TYPE_SUBCMD)
+                       sprintf(cmdstr, "%s:%s", ci->name, subcmd_name(mb));
+               else
+                       strcpy(cmdstr, ci->name);
+               printk(KERN_WARNING
+                      "mbox: unexpected command %s received!\n", cmdstr);
+               return -1;
+       }
+
+       /*
+        * if argc == 1, receive data through mbox:data register.
+        * if argc > 1, receive through ipbuf_sys.
+        */
+       if (argc == 1)
+               misc_mb_wait.retvp[0] = mb->data;
+       else if (argc > 1) {
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: %s - ipbuf_sys_da read failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       return -1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: %s - IPBUF sync failed!\n",
+                              cmdinfo[mb->cmd_h]->name);
+                       dsp_mem_disable(ipbuf_sys_da);
+                       return -1;
+               }
+               /* need word access. do not use memcpy. */
+               buf = ipbuf_sys_da->d;
+               for (i = 0; i < argc; i++)
+                       misc_mb_wait.retvp[i] = buf[i];
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+       }
+
+       misc_mb_wait.cmd_h = 0;
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return 0;
+}
+
+static int dsp_regread(enum dsp_space_e space, u16 adr, u16 *val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMR : REGRW_IOR;
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(REGRW, cmd_l, adr, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: register read error!\n");
+
+       return ret;
+}
+
+static int dsp_regwrite(enum dsp_space_e space, u16 adr, u16 val)
+{
+       u8 cmd_l = (space == SPACE_MEM) ? REGRW_MEMW : REGRW_IOW;
+       struct mb_exarg arg = {
+               .tid  = TID_ANON,
+               .argc = 1,
+               .argv = &val,
+       };
+
+       mbcompose_send_exarg(REGRW, cmd_l, adr, &arg);
+       return 0;
+}
+
+static int dsp_getvar(u8 varid, u16 *val)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(GETVAR, varid, 0, val);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: variable read error!\n");
+
+       return ret;
+}
+
+static int dsp_setvar(u8 varid, u16 val)
+{
+       mbcompose_send(SETVAR, varid, val);
+       return 0;
+}
+
+/*
+ * dsp_cfg() return value
+ *  = 0: OK
+ *  = 1: failed, but state is clear. (DSPCFG command failed)
+ *  < 0: failed. need cleanup.
+ */
+static int dsp_cfg(void)
+{
+       int ret = 0;
+
+#ifdef CONFIG_ARCH_OMAP1
+       /* for safety */
+       dsp_mem_usecount_clear();
+#endif
+
+       /*
+        * DSPCFG command and dsp_mem_start() must be called
+        * while internal mem is on.
+        */
+       dsp_mem_enable((void *)dspmem_base);
+
+       dsp_mbox_start();
+       dsp_twch_start();
+       dsp_mem_start();
+       dsp_err_start();
+
+       mbox_revision = -1;
+
+       ret = misc_mbcompose_send_and_wait(DSPCFG, DSPCFG_REQ, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINTR)
+                       printk(KERN_ERR "omapdsp: configuration error!\n");
+               ret = 1;
+               goto out;
+       }
+
+#if defined(CONFIG_ARCH_OMAP1) && defined(OLD_BINARY_SUPPORT)
+       /*
+        * MBREV 3.2 or earlier doesn't assume DMA domain is on
+        * when DSPCFG command is sent
+        */
+       if ((mbox_revision == MBREV_3_0) ||
+           (mbox_revision == MBREV_3_2)) {
+               if ((ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA)) < 0)
+                       goto out;
+       }
+#endif
+
+       if ((ret = dsp_task_config_all(n_stask)) < 0)
+               goto out;
+
+       /* initialization */
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       fbstat = FBSTAT_ENABLED;
+#endif
+
+       /* send parameter */
+       ret = dsp_setvar(VARID_ICRMASK, dsp_cpustat_get_icrmask());
+       if (ret < 0)
+               goto out;
+
+       /* create runtime sysfs entries */
+       ret = device_create_file(omap_dsp->dev, &dev_attr_loadinfo);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+ out:
+       dsp_mem_disable((void *)dspmem_base);
+       return ret;
+}
+
+static int dsp_uncfg(void)
+{
+       if (dsp_taskmod_busy()) {
+               printk(KERN_WARNING "omapdsp: tasks are busy.\n");
+               return -EBUSY;
+       }
+
+       /* FIXME: lock task module */
+
+       /* remove runtime sysfs entries */
+       device_remove_file(omap_dsp->dev, &dev_attr_loadinfo);
+
+       dsp_mbox_stop();
+       dsp_twch_stop();
+       dsp_mem_stop();
+       dsp_err_stop();
+       dsp_dbg_stop();
+       dsp_task_unconfig_all();
+       ipbuf_stop();
+
+       return 0;
+}
+
+static int dsp_suspend(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(SUSPEND, 0, 0, NULL);
+       if (ret < 0) {
+               if (ret != -EINVAL)
+                       printk(KERN_ERR "omapdsp: DSP suspend error!\n");
+               return ret;
+       }
+
+       udelay(100);    /* wait for DSP-side execution */
+       return 0;
+}
+
+int dsp_cfgstat_request(enum cfgstat_e st_req)
+{
+       static DEFINE_MUTEX(cfgstat_lock);
+       int ret = 0, ret_override = 0;
+
+       if (mutex_lock_interruptible(&cfgstat_lock))
+               return -EINTR;
+
+again:
+       switch (st_req) {
+
+       /* cfgstat takes CLEAN, READY or SUSPEND,
+          while st_req can take SUSPEND in addition. */
+
+       case CFGSTAT_CLEAN:
+               if (cfgstat == CFGSTAT_CLEAN)
+                       goto up_out;
+               if ((ret = dsp_uncfg()) < 0)
+                       goto up_out;
+               break;
+
+       case CFGSTAT_READY:
+               if (cfgstat != CFGSTAT_CLEAN) {
+                       printk(KERN_ERR "omapdsp: DSP is ready already!\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+
+               ret = dsp_cfg();
+               if (ret > 0) {  /* failed, but state is clear. */
+                       ret = -EINVAL;
+                       goto up_out;
+               } else if (ret < 0) {   /* failed, need cleanup. */
+                       st_req = CFGSTAT_CLEAN;
+                       ret_override = ret;
+                       goto again;
+               }
+               break;
+
+       /*
+        * suspend / resume
+        * DSP is not reset within this code, but done in omap_pm_suspend.
+        * so if these functions are called from sysfs,
+        * DSP should be reset / unreset out of these functions.
+        */
+       case CFGSTAT_SUSPEND:
+               switch (cfgstat) {
+
+               case CFGSTAT_CLEAN:
+                       if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
+                               printk(KERN_WARNING
+                                      "omapdsp: illegal operation -- trying "
+                                      "suspend DSP while it is running but "
+                                      "not configured.\n"
+                                      "  Resetting DSP.\n");
+                               dsp_cpustat_request(CPUSTAT_RESET);
+                               ret = -EINVAL;
+                       }
+                       goto up_out;
+
+               case CFGSTAT_READY:
+                       if ((ret = dsp_suspend()) < 0)
+                               goto up_out;
+                       break;
+
+               case CFGSTAT_SUSPEND:
+                       goto up_out;
+
+               default:
+                       BUG();
+
+               }
+
+               break;
+
+       case CFGSTAT_RESUME:
+               if (cfgstat != CFGSTAT_SUSPEND) {
+                       printk(KERN_WARNING
+                              "omapdsp: DSP resume request, but DSP is not in "
+                              "suspend state.\n");
+                       ret = -EINVAL;
+                       goto up_out;
+               }
+               st_req = CFGSTAT_READY;
+               break;
+
+       default:
+               BUG();
+
+       }
+
+       cfgstat = st_req;
+up_out:
+       mutex_unlock(&cfgstat_lock);
+       return ret_override ? ret_override : ret;
+}
+
+enum cfgstat_e dsp_cfgstat_get_stat(void)
+{
+       return cfgstat;
+}
+
+/*
+ * polls all tasks
+ */
+static int dsp_poll(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(POLL, 0, 0, NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: poll error!\n");
+
+       return ret;
+}
+
+int dsp_set_runlevel(u8 level)
+{
+       if (level == RUNLEVEL_RECOVERY) {
+               if (mbcompose_send_recovery(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       } else {
+               if ((level < RUNLEVEL_USER) ||
+                   (level > RUNLEVEL_SUPER))
+                       return -EINVAL;
+               if (mbcompose_send(RUNLEVEL, level, 0) < 0)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+static void dsp_fbctl_enable(void)
+{
+       mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_ENABLE);
+}
+
+static int dsp_fbctl_disable(void)
+{
+       int ret;
+
+       ret = misc_mbcompose_send_and_wait(KFUNC, KFUNC_FBCTL, FBCTL_DISABLE,
+                                          NULL);
+       if ((ret < 0) && (ret != -EINTR))
+               printk(KERN_ERR "omapdsp: fb disable error!\n");
+
+       return 0;
+}
+
+static int dsp_fbstat_request(enum fbstat_e st)
+{
+       static DEFINE_MUTEX(fbstat_lock);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&fbstat_lock))
+               return -EINTR;
+
+       if (st == fbstat)
+               goto up_out;
+
+       switch (st) {
+       case FBSTAT_ENABLED:
+               dsp_fbctl_enable();
+               break;
+       case FBSTAT_DISABLED:
+               if ((ret = dsp_fbctl_disable()) < 0)
+                       goto up_out;
+               break;
+       default:
+               BUG();
+       }
+
+       fbstat = st;
+up_out:
+       mutex_unlock(&fbstat_lock);
+       return 0;
+}
+#endif /* CONFIG_OMAP_DSP_FBEXPORT */
+
+/*
+ * DSP control device file operations
+ */
+static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       /*
+        * command level 1: commands which don't need lock
+        */
+       case DSPCTL_IOCTL_RUN:
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_RESET:
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_SETRSTVECT:
+               ret = dsp_set_rstvect((dsp_long_t)arg);
+               break;
+
+#ifdef CONFIG_ARCH_OMAP1
+       case DSPCTL_IOCTL_CPU_IDLE:
+               dsp_cpustat_request(CPUSTAT_CPU_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_GBL_IDLE:
+               dsp_cpustat_request(CPUSTAT_GBL_IDLE);
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_ON:
+               mpui_wordswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_WORDSWAP_OFF:
+               mpui_wordswap_off();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_ON:
+               mpui_byteswap_on();
+               break;
+
+       case DSPCTL_IOCTL_MPUI_BYTESWAP_OFF:
+               mpui_byteswap_off();
+               break;
+#endif /* CONFIG_ARCH_OMAP1 */
+
+       case DSPCTL_IOCTL_TASKCNT:
+               ret = dsp_task_count();
+               break;
+
+       case DSPCTL_IOCTL_MBSEND:
+               {
+                       struct omap_dsp_mailbox_cmd u_cmd;
+                       mbox_msg_t msg;
+                       if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd)))
+                               return -EFAULT;
+                       msg = (u_cmd.cmd << 16) | u_cmd.data;
+                       ret = dsp_mbcmd_send((struct mbcmd *)&msg);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_SETVAR:
+               {
+                       struct omap_dsp_varinfo var;
+                       if (copy_from_user(&var, (void *)arg, sizeof(var)))
+                               return -EFAULT;
+                       ret = dsp_setvar(var.varid, var.val[0]);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_RUNLEVEL:
+               ret = dsp_set_runlevel(arg);
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBEN:
+               ret = dsp_fbstat_request(FBSTAT_ENABLED);
+               break;
+#endif
+
+       /*
+        * command level 2: commands which need lock
+        */
+       case DSPCTL_IOCTL_DSPCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_READY);
+               break;
+
+       case DSPCTL_IOCTL_DSPUNCFG:
+               ret = dsp_cfgstat_request(CFGSTAT_CLEAN);
+               break;
+
+       case DSPCTL_IOCTL_POLL:
+               ret = dsp_poll();
+               break;
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case DSPCTL_IOCTL_FBDIS:
+               ret = dsp_fbstat_request(FBSTAT_DISABLED);
+               break;
+#endif
+
+       case DSPCTL_IOCTL_SUSPEND:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_SUSPEND)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RESET);
+               break;
+
+       case DSPCTL_IOCTL_RESUME:
+               if ((ret = dsp_cfgstat_request(CFGSTAT_RESUME)) < 0)
+                       break;
+               dsp_cpustat_request(CPUSTAT_RUN);
+               break;
+
+       case DSPCTL_IOCTL_REGMEMR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_MEM, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGMEMW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_MEM, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOR:
+               {
+                       struct omap_dsp_reginfo *u_reg = (void *)arg;
+                       u16 adr, val;
+
+                       if (copy_from_user(&adr, &u_reg->adr, sizeof(u16)))
+                               return -EFAULT;
+                       if ((ret = dsp_regread(SPACE_IO, adr, &val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_reg->val, &val, sizeof(u16)))
+                               return -EFAULT;
+                       break;
+               }
+
+       case DSPCTL_IOCTL_REGIOW:
+               {
+                       struct omap_dsp_reginfo reg;
+
+                       if (copy_from_user(&reg, (void *)arg, sizeof(reg)))
+                               return -EFAULT;
+                       ret = dsp_regwrite(SPACE_IO, reg.adr, reg.val);
+                       break;
+               }
+
+       case DSPCTL_IOCTL_GETVAR:
+               {
+                       struct omap_dsp_varinfo *u_var = (void *)arg;
+                       u8 varid;
+                       u16 val[5]; /* maximum */
+                       int argc;
+
+                       if (copy_from_user(&varid, &u_var->varid, sizeof(u8)))
+                               return -EFAULT;
+                       switch (varid) {
+                       case VARID_ICRMASK:
+                               argc = 1;
+                               break;
+                       case VARID_LOADINFO:
+                               argc = 5;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       if ((ret = dsp_getvar(varid, val)) < 0)
+                               return ret;
+                       if (copy_to_user(&u_var->val, val, sizeof(u16) * argc))
+                               return -EFAULT;
+                       break;
+               }
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_suspend(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_dspcfg(struct mbcmd *mb)
+{
+       u8 last   = mb->cmd_l & 0x80;
+       u8 cfgcmd = mb->cmd_l & 0x7f;
+       static dsp_long_t tmp_ipb_adr;
+
+       if (!waitqueue_active(&misc_mb_wait.wait_q) ||
+           (misc_mb_wait.cmd_h != MBOX_CMD_DSP_DSPCFG)) {
+               printk(KERN_WARNING
+                      "mbox: DSPCFG command received, "
+                      "but nobody is waiting for it...\n");
+               return;
+       }
+
+       /* mailbox protocol check */
+       if (cfgcmd == DSPCFG_PROTREV) {
+               mbox_revision = mb->data;
+               if (mbox_revision == MBPROT_REVISION)
+                       return;
+#ifdef OLD_BINARY_SUPPORT
+               else if ((mbox_revision == MBREV_3_0) ||
+                        (mbox_revision == MBREV_3_2)) {
+                       printk(KERN_WARNING
+                              "mbox: ***** old DSP binary *****\n"
+                              "  Please update your DSP application.\n");
+                       return;
+               }
+#endif
+               else {
+                       printk(KERN_ERR
+                              "mbox: protocol revision check error!\n"
+                              "  expected=0x%04x, received=0x%04x\n",
+                              MBPROT_REVISION, mb->data);
+                       mbox_revision = -1;
+                       goto abort1;
+               }
+       }
+
+       /*
+        * following commands are accepted only after
+        * revision check has been passed.
+        */
+       if (!mbox_revision < 0) {
+               pr_info("mbox: DSPCFG command received, "
+                       "but revision check has not been passed.\n");
+               return;
+       }
+
+       switch (cfgcmd) {
+       case DSPCFG_SYSADRH:
+               tmp_ipb_adr = (u32)mb->data << 16;
+               break;
+
+       case DSPCFG_SYSADRL:
+               tmp_ipb_adr |= mb->data;
+               break;
+
+       case DSPCFG_ABORT:
+               goto abort1;
+
+       default:
+               printk(KERN_ERR
+                      "mbox: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n",
+                      mb->cmd_l, mb->data);
+               return;
+       }
+
+       if (last) {
+               void *badr;
+               u16 bln;
+               u16 bsz;
+               volatile u16 *buf;
+               void *ipb_sys_da, *ipb_sys_ad;
+               void *mbseq;     /* FIXME: 3.4 obsolete */
+               short *dbg_buf;
+               u16 dbg_buf_sz, dbg_line_sz;
+               struct mem_sync_struct mem_sync, *mem_syncp;
+
+               ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
+               if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
+                       goto abort1;
+
+               if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - ipbuf_sys_da read failed!\n");
+                       goto abort1;
+               }
+               if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 10) < 0) {
+                       printk(KERN_ERR "mbox: DSPCFG - IPBUF sync failed!\n");
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+               /*
+                * read configuration data on system IPBUF
+                * we must read with 16bit-access
+                */
+#ifdef OLD_BINARY_SUPPORT
+               if (mbox_revision == MBPROT_REVISION) {
+#endif
+                       buf = ipbuf_sys_da->d;
+                       n_stask        = buf[0];
+                       bln            = buf[1];
+                       bsz            = buf[2];
+                       badr           = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da     = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad     = MKVIRT(buf[7], buf[8]);
+                       mbseq          = MKVIRT(buf[9], buf[10]);
+                       dbg_buf        = MKVIRT(buf[11], buf[12]);
+                       dbg_buf_sz     = buf[13];
+                       dbg_line_sz    = buf[14];
+                       mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
+                       mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
+                       mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
+                       mem_syncp = &mem_sync;
+#ifdef OLD_BINARY_SUPPORT
+               } else if (mbox_revision == MBREV_3_2) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* ipb_sys_da  = MKVIRT(buf[5], buf[6]); */
+                       ipb_sys_ad  = MKVIRT(buf[7], buf[8]);
+                       mbseq       = MKVIRT(buf[9], buf[10]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else if (mbox_revision == MBREV_3_0) {
+                       buf = ipbuf_sys_da->d;
+                       n_stask     = buf[0];
+                       bln         = buf[1];
+                       bsz         = buf[2];
+                       badr        = MKVIRT(buf[3], buf[4]);
+                       /* bkeep       = buf[5]; */
+                       /* ipb_sys_da  = MKVIRT(buf[6], buf[7]); */
+                       ipb_sys_ad  = MKVIRT(buf[8], buf[9]);
+                       mbseq       = MKVIRT(buf[10], buf[11]);
+                       dbg_buf     = NULL;
+                       dbg_buf_sz  = 0;
+                       dbg_line_sz = 0;
+                       mem_syncp   = NULL;
+               } else { /* should not occur */
+                       dsp_mem_disable(ipbuf_sys_da);
+                       goto abort1;
+               }
+#endif /* OLD_BINARY_SUPPORT */
+
+               release_ipbuf_pvt(ipbuf_sys_da);
+               dsp_mem_disable(ipbuf_sys_da);
+
+               /*
+                * following configurations need to be done before
+                * waking up the dspcfg initiator process.
+                */
+               if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
+                       goto abort1;
+               if (ipbuf_config(bln, bsz, badr) < 0)
+                       goto abort1;
+               if (dsp_mbox_config(mbseq) < 0)
+                       goto abort2;
+               if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
+                       goto abort2;
+               if (dsp_mem_sync_config(mem_syncp) < 0)
+                       goto abort2;
+
+               misc_mb_wait.cmd_h = 0;
+               wake_up_interruptible(&misc_mb_wait.wait_q);
+       }
+       return;
+
+abort2:
+       ipbuf_stop();
+abort1:
+       wake_up_interruptible(&misc_mb_wait.wait_q);
+       return;
+}
+
+void mbox_poll(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+void mbox_regrw(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case REGRW_DATA:
+               misc_mbcmd_response(mb, 1, 0);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal REGRW command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_getvar(struct mbcmd *mb)
+{
+       switch (mb->cmd_l) {
+       case VARID_ICRMASK:
+               misc_mbcmd_response(mb, 1, 1);
+               break;
+       case VARID_LOADINFO:
+               misc_mbcmd_response(mb, 5, 1);
+               break;
+       default:
+               printk(KERN_ERR
+                      "mbox: Illegal GETVAR command: "
+                      "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data);
+               return;
+       }
+}
+
+void mbox_fbctl_disable(struct mbcmd *mb)
+{
+       misc_mbcmd_response(mb, 0, 0);
+}
+
+struct file_operations dsp_ctl_fops = {
+       .owner   = THIS_MODULE,
+       .ioctl   = dsp_ctl_ioctl,
+};
+
+/*
+ * sysfs files
+ */
+
+/* ifver */
+static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+
+       /*
+        * I/F VERSION descriptions:
+        *
+        * 3.2: sysfs / udev support
+        *      KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
+        * 3.3: added following ioctls
+        *      DSPCTL_IOCTL_GBL_IDLE
+        *      DSPCTL_IOCTL_CPU_IDLE (instead of DSPCTL_IOCTL_IDLE)
+        *      DSPCTL_IOCTL_POLL
+        */
+
+       /*
+        * print all supporting I/F VERSIONs, like followings.
+        *
+        * len += sprintf(buf, "3.2\n");
+        * len += sprintf(buf, "3.3\n");
+        */
+       len += sprintf(buf + len, "3.2\n");
+       len += sprintf(buf + len, "3.3\n");
+
+       return len;
+}
+
+/* cpustat */
+static char *cpustat_name[CPUSTAT_MAX] = {
+       [CPUSTAT_RESET]    = "reset",
+#ifdef CONFIG_ARCH_OMAP1
+       [CPUSTAT_GBL_IDLE] = "gbl_idle",
+       [CPUSTAT_CPU_IDLE] = "cpu_idle",
+#endif
+       [CPUSTAT_RUN]      = "run",
+};
+
+static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", cpustat_name[dsp_cpustat_get_stat()]);
+}
+
+/* icrmask */
+static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
+}
+
+static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       u16 mask;
+       int ret;
+
+       mask = simple_strtol(buf, NULL, 16);
+       dsp_cpustat_set_icrmask(mask);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+               ret = dsp_setvar(VARID_ICRMASK, mask);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return count;
+}
+
+/* loadinfo */
+static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       int len;
+       int ret;
+       u16 val[5];
+
+       if ((ret = dsp_getvar(VARID_LOADINFO, val)) < 0)
+               return ret;
+
+       /*
+        * load info value range is 0(free) - 10000(busy):
+        * if CPU load is not measured on DSP, it sets 0xffff at val[0].
+        */
+
+       if (val[0] == 0xffff) {
+               len = sprintf(buf,
+                             "currently DSP load info is not available.\n");
+               goto out;
+       }
+
+       len = sprintf(buf,
+                     "DSP load info:\n"
+                     "  10ms average = %3d.%02d%%\n"
+                     "  1sec average = %3d.%02d%%  busiest 10ms = %3d.%02d%%\n"
+                     "  1min average = %3d.%02d%%  busiest 1s   = %3d.%02d%%\n",
+                     val[0]/100, val[0]%100,
+                     val[1]/100, val[1]%100, val[2]/100, val[2]%100,
+                     val[3]/100, val[3]%100, val[4]/100, val[4]%100);
+out:
+       return len;
+}
+
+int __init dsp_ctl_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ifver);
+       if (unlikely(ret))
+               return ret;
+       ret = device_create_file(omap_dsp->dev, &dev_attr_cpustat);
+       if (unlikely(ret))
+               goto fail_create_cpustat;
+       ret = device_create_file(omap_dsp->dev, &dev_attr_icrmask);
+       if (unlikely(ret))
+               goto fail_create_icrmask;
+
+       return 0;
+
+fail_create_icrmask:
+       device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+fail_create_cpustat:
+       device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+
+       return ret;
+}
+
+void dsp_ctl_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_ifver);
+       device_remove_file(omap_dsp->dev, &dev_attr_cpustat);
+       device_remove_file(omap_dsp->dev, &dev_attr_icrmask);
+}
diff --git a/drivers/dsp/dspgateway/dsp_ctl_core.c b/drivers/dsp/dspgateway/dsp_ctl_core.c
new file mode 100644 (file)
index 0000000..25954bb
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "dsp.h"
+
+#define CTL_MINOR      0
+#define MEM_MINOR      1
+#define TWCH_MINOR     2
+#define ERR_MINOR      3
+
+static struct class *dsp_ctl_class;
+extern struct file_operations dsp_ctl_fops,
+                             dsp_mem_fops,
+                             dsp_twch_fops,
+                             dsp_err_fops;
+
+static int dsp_ctl_core_open(struct inode *inode, struct file *file)
+{
+       static DEFINE_MUTEX(open_lock);
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&open_lock))
+               return -EINTR;
+       if (omap_dsp->initialized == 0) {
+               ret = dsp_late_init();
+               if (ret != 0) {
+                       mutex_unlock(&open_lock);
+                       return ret;
+               }
+               omap_dsp->initialized = 1;
+       }
+       mutex_unlock(&open_lock);
+
+       switch (iminor(inode)) {
+       case CTL_MINOR:
+               file->f_op = &dsp_ctl_fops;
+               break;
+       case MEM_MINOR:
+               file->f_op = &dsp_mem_fops;
+               break;
+       case TWCH_MINOR:
+               file->f_op = &dsp_twch_fops;
+               break;
+       case ERR_MINOR:
+               file->f_op = &dsp_err_fops;
+               break;
+       default:
+               return -ENXIO;
+       }
+       if (file->f_op && file->f_op->open)
+               return file->f_op->open(inode, file);
+       return 0;
+}
+
+static struct file_operations dsp_ctl_core_fops = {
+       .owner = THIS_MODULE,
+       .open  = dsp_ctl_core_open,
+};
+
+static const struct dev_list {
+       unsigned int    minor;
+       char            *devname;
+       umode_t         mode;
+} dev_list[] = {
+       {CTL_MINOR,  "dspctl",  S_IRUSR | S_IWUSR},
+       {MEM_MINOR,  "dspmem",  S_IRUSR | S_IWUSR | S_IRGRP},
+       {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
+       {ERR_MINOR,  "dsperr",  S_IRUSR | S_IRGRP},
+};
+
+int __init dsp_ctl_core_init(void)
+{
+       int retval;
+       int i;
+
+       retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl",
+                                &dsp_ctl_core_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register dspctl device: %d\n",
+                      retval);
+               return retval;
+       }
+
+       dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               device_create(dsp_ctl_class, NULL,
+                             MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor),
+                             NULL, dev_list[i].devname);
+       }
+
+       return 0;
+}
+
+void dsp_ctl_core_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
+               device_destroy(dsp_ctl_class,
+                               MKDEV(OMAP_DSP_CTL_MAJOR,
+                                       dev_list[i].minor));
+       }
+       class_destroy(dsp_ctl_class);
+
+       unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
+}
diff --git a/drivers/dsp/dspgateway/dsp_mbcmd.h b/drivers/dsp/dspgateway/dsp_mbcmd.h
new file mode 100644 (file)
index 0000000..fb35749
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_MBCMD_H
+#define __PLAT_OMAP_DSP_MBCMD_H
+/*
+ * mailbox command: 0x00 - 0x7f
+ * when a driver wants to use mailbox, it must reserve mailbox commands here.
+ */
+#define MBOX_CMD_DSP_WDSND     0x10
+#define MBOX_CMD_DSP_WDREQ     0x11
+#define MBOX_CMD_DSP_BKSND     0x20
+#define MBOX_CMD_DSP_BKREQ     0x21
+#define MBOX_CMD_DSP_BKYLD     0x23
+#define MBOX_CMD_DSP_BKSNDP    0x24
+#define MBOX_CMD_DSP_BKREQP    0x25
+#define MBOX_CMD_DSP_TCTL      0x30
+#define MBOX_CMD_DSP_TCTLDATA  0x31
+#define MBOX_CMD_DSP_POLL      0x32
+#define MBOX_CMD_DSP_WDT       0x50
+#define MBOX_CMD_DSP_RUNLEVEL  0x51
+#define MBOX_CMD_DSP_PM                0x52
+#define MBOX_CMD_DSP_SUSPEND   0x53
+#define MBOX_CMD_DSP_KFUNC     0x54
+#define MBOX_CMD_DSP_TCFG      0x60
+#define MBOX_CMD_DSP_TADD      0x62
+#define MBOX_CMD_DSP_TDEL      0x63
+#define MBOX_CMD_DSP_TSTOP     0x65
+#define MBOX_CMD_DSP_DSPCFG    0x70
+#define MBOX_CMD_DSP_REGRW     0x72
+#define MBOX_CMD_DSP_GETVAR    0x74
+#define MBOX_CMD_DSP_SETVAR    0x75
+#define MBOX_CMD_DSP_ERR       0x78
+#define MBOX_CMD_DSP_DBG       0x79
+
+/*
+ * DSP mailbox protocol definitions
+ */
+#define MBPROT_REVISION        0x0019
+
+#define TCTL_TINIT             0x0000
+#define TCTL_TEN               0x0001
+#define TCTL_TDIS              0x0002
+#define TCTL_TCLR              0x0003
+#define TCTL_TCLR_FORCE                0x0004
+
+#define RUNLEVEL_USER          0x01
+#define RUNLEVEL_SUPER         0x0e
+#define RUNLEVEL_RECOVERY      0x10
+
+#define PM_DISABLE             0x00
+#define PM_ENABLE              0x01
+
+#define KFUNC_FBCTL            0x00
+#define KFUNC_POWER            0x01
+
+#define FBCTL_UPD              0x0000
+#define FBCTL_ENABLE           0x0002
+#define FBCTL_DISABLE          0x0003
+
+/* KFUNC_POWER */
+#define AUDIO_PWR_UP           0x0000  /* ARM(exe/ack) <->  DSP(req)   */
+#define AUDIO_PWR_DOWN         0x0001  /* ARM(exe)     <-  DSP(req)    */
+#define AUDIO_PWR_DOWN1                AUDIO_PWR_DOWN
+#define AUDIO_PWR_DOWN2                0x0002
+#define DSP_PWR_UP             0x0003  /* ARM(exe/snd) ->  DSP(exe)    */
+#define DSP_PWR_DOWN           0x0004  /* ARM(exe)     <-  DSP(req)    */
+#define DVFS_START             0x0006  /* ARM(req)     <-> DSP(exe/ack)*/
+#define DVFS_STOP              0x0007  /* ARM(req)      -> DSP(exe)    */
+
+#define TDEL_SAFE              0x0000
+#define TDEL_KILL              0x0001
+
+#define DSPCFG_REQ             0x00
+#define DSPCFG_SYSADRH         0x28
+#define DSPCFG_SYSADRL         0x29
+#define DSPCFG_PROTREV         0x70
+#define DSPCFG_ABORT           0x78
+#define DSPCFG_LAST            0x80
+
+#define REGRW_MEMR             0x00
+#define REGRW_MEMW             0x01
+#define REGRW_IOR              0x02
+#define REGRW_IOW              0x03
+#define REGRW_DATA             0x04
+
+#define VARID_ICRMASK          0x00
+#define VARID_LOADINFO         0x01
+
+#define TTYP_ARCV              0x0001
+#define TTYP_ASND              0x0002
+#define TTYP_BKMD              0x0004
+#define TTYP_BKDM              0x0008
+#define TTYP_PVMD              0x0010
+#define TTYP_PVDM              0x0020
+
+#define EID_BADTID             0x10
+#define EID_BADTCN             0x11
+#define EID_BADBID             0x20
+#define EID_BADCNT             0x21
+#define EID_NOTLOCKED          0x22
+#define EID_STVBUF             0x23
+#define EID_BADADR             0x24
+#define EID_BADTCTL            0x30
+#define EID_BADPARAM           0x50
+#define EID_FATAL              0x58
+#define EID_NOMEM              0xc0
+#define EID_NORES              0xc1
+#define EID_IPBFULL            0xc2
+#define EID_WDT                        0xd0
+#define EID_TASKNOTRDY         0xe0
+#define EID_TASKBSY            0xe1
+#define EID_TASKERR            0xef
+#define EID_BADCFGTYP          0xf0
+#define EID_DEBUG              0xf8
+#define EID_BADSEQ             0xfe
+#define EID_BADCMD             0xff
+
+#define TNM_LEN                        16
+
+#define TID_FREE               0xff
+#define TID_ANON               0xfe
+
+#define BID_NULL               0xffff
+#define BID_PVT                        0xfffe
+
+#endif /* __PLAT_OMAP_DSP_MBCMD_H */
diff --git a/drivers/dsp/dspgateway/dsp_mem.c b/drivers/dsp/dspgateway/dsp_mem.c
new file mode 100644 (file)
index 0000000..e21bd06
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * Conversion to mempool API and ARM MMU section mapping
+ * by Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mempool.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <mach/tc.h>
+#include <mach/omapfb.h>
+#include <mach/dsp.h>
+#include <mach/mailbox.h>
+#include <mach/mmu.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+#if 0
+#if defined(CONFIG_ARCH_OMAP1)
+#include "../../mach-omap1/mmu.h"
+#elif defined(CONFIG_ARCH_OMAP2)
+#include "../../mach-omap2/mmu.h"
+#endif
+#endif
+
+#include "mmu.h"
+
+static struct mem_sync_struct mem_sync;
+
+int dsp_mem_sync_inc(void)
+{
+       if (dsp_mem_enable((void *)dspmem_base) < 0)
+               return -1;
+       if (mem_sync.DARAM)
+               mem_sync.DARAM->ad_arm++;
+       if (mem_sync.SARAM)
+               mem_sync.SARAM->ad_arm++;
+       if (mem_sync.SDRAM)
+               mem_sync.SDRAM->ad_arm++;
+       dsp_mem_disable((void *)dspmem_base);
+
+       return 0;
+}
+
+/*
+ * dsp_mem_sync_config() is called from mbox1 workqueue
+ */
+int dsp_mem_sync_config(struct mem_sync_struct *sync)
+{
+       size_t sync_seq_sz = sizeof(struct sync_seq);
+
+#ifdef OLD_BINARY_SUPPORT
+       if (sync == NULL) {
+               memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+               return 0;
+       }
+#endif
+       if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
+           (dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
+           (dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
+               printk(KERN_ERR
+                      "omapdsp: mem_sync address validation failure!\n"
+                      "  mem_sync.DARAM = 0x%p,\n"
+                      "  mem_sync.SARAM = 0x%p,\n"
+                      "  mem_sync.SDRAM = 0x%p,\n",
+                      sync->DARAM, sync->SARAM, sync->SDRAM);
+               return -1;
+       }
+
+       memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
+
+       return 0;
+}
+
+
+enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
+{
+       void *ds = (void *)daram_base;
+       void *de = (void *)daram_base + daram_size;
+       void *ss = (void *)saram_base;
+       void *se = (void *)saram_base + saram_size;
+       int ret;
+
+       if ((vadr >= ds) && (vadr < de)) {
+               if (vadr + len > de)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_DARAM;
+       } else if ((vadr >= ss) && (vadr < se)) {
+               if (vadr + len > se)
+                       return MEM_TYPE_CROSSING;
+               else
+                       return MEM_TYPE_SARAM;
+       } else {
+               down_read(&dsp_mmu.exmap_sem);
+               if (exmap_valid(&dsp_mmu, vadr, len))
+                       ret = MEM_TYPE_EXTERN;
+               else
+                       ret = MEM_TYPE_NONE;
+               up_read(&dsp_mmu.exmap_sem);
+               return ret;
+       }
+}
+
+int dsp_address_validate(void *p, size_t len, char *fmt, ...)
+{
+       char s[64];
+       va_list args;
+
+       if (dsp_mem_type(p, len) > 0)
+               return 0;
+
+       if (fmt == NULL)
+               goto out;
+
+       va_start(args, fmt);
+       vsprintf(s, fmt, args);
+       va_end(args);
+       printk(KERN_ERR
+              "omapdsp: %s address(0x%p) and size(0x%x) is not valid!\n"
+              "(crossing different type of memories, or external memory\n"
+              "space where no actual memory is mapped)\n", s, p, len);
+ out:
+       return -1;
+}
+
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+
+static inline unsigned long lineup_offset(unsigned long adr,
+                                         unsigned long ref,
+                                         unsigned long mask)
+{
+       unsigned long newadr;
+
+       newadr = (adr & ~mask) | (ref & mask);
+       if (newadr < adr)
+               newadr += mask + 1;
+       return newadr;
+}
+
+/*
+ * fb update functions:
+ * fbupd_response() is executed by the workqueue.
+ * fbupd_cb() is called when fb update is done, in interrupt context.
+ * mbox_fbupd() is called when KFUNC:FBCTL:UPD is received from DSP.
+ */
+static void fbupd_response(struct work_struct *unused)
+{
+       int status;
+
+       status = mbcompose_send(KFUNC, KFUNC_FBCTL, FBCTL_UPD);
+       if (status == 0)
+               return;
+
+       /* FIXME: DSP is busy !! */
+       printk(KERN_ERR
+              "omapdsp:"
+              "DSP is busy when trying to send FBCTL:UPD response!\n");
+}
+
+static DECLARE_WORK(fbupd_response_work, fbupd_response);
+
+static void fbupd_cb(void *arg)
+{
+       schedule_work(&fbupd_response_work);
+}
+
+void mbox_fbctl_upd(void)
+{
+       struct omapfb_update_window win;
+       volatile unsigned short *buf = ipbuf_sys_da->d;
+
+       if (sync_with_dsp(&ipbuf_sys_da->s, TID_ANON, 5000) < 0) {
+               printk(KERN_ERR "mbox: FBCTL:UPD - IPBUF sync failed!\n");
+               return;
+       }
+       win.x = buf[0];
+       win.y = buf[1];
+       win.width = buf[2];
+       win.height = buf[3];
+       win.format = buf[4];
+       release_ipbuf_pvt(ipbuf_sys_da);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       if (!omapfb_ready) {
+               printk(KERN_WARNING
+                      "omapdsp: fbupd() called while HWA742 is not ready!\n");
+               return;
+       }
+#endif
+       omapfb_update_window_async(registered_fb[0], &win, fbupd_cb, NULL);
+}
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static int omapfb_notifier_cb(struct notifier_block *omapfb_nb,
+                             unsigned long event, void *fbi)
+{
+       pr_info("omapfb_notifier_cb(): event = %s\n",
+               (event == OMAPFB_EVENT_READY)    ? "READY" :
+               (event == OMAPFB_EVENT_DISABLED) ? "DISABLED" : "Unknown");
+       if (event == OMAPFB_EVENT_READY)
+               omapfb_ready = 1;
+       else if (event == OMAPFB_EVENT_DISABLED)
+               omapfb_ready = 0;
+       return 0;
+}
+#endif
+
+static int dsp_fbexport(dsp_long_t *dspadr)
+{
+       dsp_long_t dspadr_actual;
+       unsigned long padr_sys, padr, fbsz_sys, fbsz;
+       int cnt;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       int status;
+#endif
+
+       pr_debug( "omapdsp: frame buffer export\n");
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       if (omapfb_nb) {
+               printk(KERN_WARNING
+                      "omapdsp: frame buffer has been exported already!\n");
+               return -EBUSY;
+       }
+#endif
+
+       if (num_registered_fb == 0) {
+               pr_info("omapdsp: frame buffer not registered.\n");
+               return -EINVAL;
+       }
+       if (num_registered_fb != 1) {
+               pr_info("omapdsp: %d frame buffers found. we use first one.\n",
+                       num_registered_fb);
+       }
+       padr_sys = registered_fb[0]->fix.smem_start;
+       fbsz_sys = registered_fb[0]->fix.smem_len;
+       if (fbsz_sys == 0) {
+               printk(KERN_ERR
+                      "omapdsp: framebuffer doesn't seem to be configured "
+                      "correctly! (size=0)\n");
+               return -EINVAL;
+       }
+
+       /*
+        * align padr and fbsz to 4kB boundary
+        * (should be noted to the user afterwards!)
+        */
+       padr = padr_sys & ~(SZ_4K-1);
+       fbsz = (fbsz_sys + padr_sys - padr + SZ_4K-1) & ~(SZ_4K-1);
+
+       /* line up dspadr offset with padr */
+       dspadr_actual =
+               (fbsz > SZ_1M) ?  lineup_offset(*dspadr, padr, SZ_1M-1) :
+               (fbsz > SZ_64K) ? lineup_offset(*dspadr, padr, SZ_64K-1) :
+               /* (fbsz > SZ_4KB) ? */ *dspadr;
+       if (dspadr_actual != *dspadr)
+               pr_debug(
+                       "omapdsp: actual dspadr for FBEXPORT = %08x\n",
+                       dspadr_actual);
+       *dspadr = dspadr_actual;
+
+       cnt = omap_mmu_exmap(&dsp_mmu, dspadr_actual, padr, fbsz,
+                            EXMAP_TYPE_FB);
+       if (cnt < 0) {
+               printk(KERN_ERR "omapdsp: exmap failure.\n");
+               return cnt;
+       }
+
+       if ((padr != padr_sys) || (fbsz != fbsz_sys)) {
+               printk(KERN_WARNING
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+"  !!  screen base address or size is not aligned in 4kB:           !!\n"
+"  !!    actual screen  adr = %08lx, size = %08lx                   !!\n"
+"  !!    exporting      adr = %08lx, size = %08lx                   !!\n"
+"  !!  Make sure that the framebuffer is allocated with 4kB-order!  !!\n"
+"  !!  Otherwise DSP can corrupt the kernel memory.                 !!\n"
+"  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",
+                      padr_sys, fbsz_sys, padr, fbsz);
+       }
+
+       /* increase the DMA priority */
+       set_emiff_dma_prio(15);
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+       omapfb_nb = kzalloc(sizeof(struct omapfb_notifier_block), GFP_KERNEL);
+       if (omapfb_nb == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: failed to allocate memory for omapfb_nb!\n");
+               omap_mmu_exunmap(&dsp_mmu, (unsigned long)dspadr);
+               return -ENOMEM;
+       }
+
+       status = omapfb_register_client(omapfb_nb, omapfb_notifier_cb, NULL);
+       if (status)
+               pr_info("omapfb_register_client(): failure(%d)\n", status);
+#endif
+
+       return cnt;
+}
+#else
+void mbox_fbctl_upd(void) { }
+#endif
+
+/* dsp/mem fops: backward compatibility */
+static ssize_t dsp_mem_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       struct bin_attribute attr;
+
+       return __omap_mmu_mem_read(&dsp_mmu, &attr,
+                                  (char __user *)buf, *ppos, count);
+}
+
+static ssize_t dsp_mem_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       struct bin_attribute attr;
+
+       return __omap_mmu_mem_write(&dsp_mmu, &attr,
+                                   (char __user *)buf, *ppos, count);
+}
+
+static int dsp_mem_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct omap_dsp_mapinfo mapinfo;
+       __u32 size;
+
+       switch (cmd) {
+       case MEM_IOCTL_MMUINIT:
+               if (dsp_mmu.exmap_tbl)
+                       omap_mmu_unregister(&dsp_mmu);
+               dsp_mem_ipi_init();
+               return omap_mmu_register(&dsp_mmu);
+
+       case MEM_IOCTL_EXMAP:
+               if (copy_from_user(&mapinfo, (void __user *)arg,
+                                  sizeof(mapinfo)))
+                       return -EFAULT;
+               return omap_mmu_exmap(&dsp_mmu, mapinfo.dspadr,
+                                     0, mapinfo.size, EXMAP_TYPE_MEM);
+
+       case MEM_IOCTL_EXUNMAP:
+               return omap_mmu_exunmap(&dsp_mmu, (unsigned long)arg);
+
+       case MEM_IOCTL_EXMAP_FLUSH:
+               omap_mmu_exmap_flush(&dsp_mmu);
+               return 0;
+#ifdef CONFIG_OMAP_DSP_FBEXPORT
+       case MEM_IOCTL_FBEXPORT:
+       {
+               dsp_long_t dspadr;
+               int ret;
+               if (copy_from_user(&dspadr, (void __user *)arg,
+                                  sizeof(dsp_long_t)))
+                       return -EFAULT;
+               ret = dsp_fbexport(&dspadr);
+               if (copy_to_user((void __user *)arg, &dspadr,
+                                sizeof(dsp_long_t)))
+                       return -EFAULT;
+               return ret;
+       }
+#endif
+       case MEM_IOCTL_MMUITACK:
+               return dsp_mmu_itack();
+
+       case MEM_IOCTL_KMEM_RESERVE:
+
+               if (copy_from_user(&size, (void __user *)arg,
+                                  sizeof(__u32)))
+                       return -EFAULT;
+               return omap_mmu_kmem_reserve(&dsp_mmu, size);
+
+
+       case MEM_IOCTL_KMEM_RELEASE:
+               omap_mmu_kmem_release();
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+struct file_operations dsp_mem_fops = {
+       .owner   = THIS_MODULE,
+       .read    = dsp_mem_read,
+       .write   = dsp_mem_write,
+       .ioctl   = dsp_mem_ioctl,
+};
+
+void dsp_mem_start(void)
+{
+       dsp_register_mem_cb(intmem_enable, intmem_disable);
+}
+
+void dsp_mem_stop(void)
+{
+       memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
+       dsp_unregister_mem_cb();
+}
+
+static void dsp_mmu_irq_work(struct work_struct *work)
+{
+       struct omap_mmu *mmu = container_of(work, struct omap_mmu, irq_work);
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY) {
+               dsp_err_set(ERRCODE_MMU, mmu->fault_address);
+               return;
+       }
+       omap_mmu_itack(mmu);
+       pr_info("Resetting DSP...\n");
+       dsp_cpustat_request(CPUSTAT_RESET);
+       omap_mmu_enable(mmu, 0);
+}
+
+/*
+ * later half of dsp memory initialization
+ */
+int dsp_mem_late_init(void)
+{
+       int ret;
+
+       dsp_mem_ipi_init();
+
+       INIT_WORK(&dsp_mmu.irq_work, dsp_mmu_irq_work);
+       ret = omap_mmu_register(&dsp_mmu);
+       if (ret) {
+               dsp_reset_idle_boot_base();
+               goto out;
+       }
+       omap_dsp->mmu = &dsp_mmu;
+ out:
+       return ret;
+}
+
+int __init dsp_mem_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP2
+       dsp_mmu.clk    = dsp_fck_handle;
+       dsp_mmu.memclk = dsp_ick_handle;
+#elif defined(CONFIG_ARCH_OMAP1)
+       dsp_mmu.clk    = dsp_ck_handle;
+       dsp_mmu.memclk = api_ck_handle;
+#endif
+       return 0;
+}
+
+void dsp_mem_exit(void)
+{
+       dsp_reset_idle_boot_base();
+       omap_mmu_unregister(&dsp_mmu);
+}
diff --git a/drivers/dsp/dspgateway/error.c b/drivers/dsp/dspgateway/error.c
new file mode 100644 (file)
index 0000000..66d9c8a
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <mach/mailbox.h>
+#include <asm/uaccess.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+/*
+ * value seen through read()
+ */
+#define DSP_ERR_WDT    0x00000001
+#define DSP_ERR_MMU    0x00000002
+static unsigned long errval;
+
+static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
+static int errcnt;
+static u16 wdtval;     /* FIXME: read through ioctl */
+static u32 mmu_fadr;   /* FIXME: read through ioctl */
+
+/*
+ * DSP error detection device file operations
+ */
+static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       unsigned long flags;
+       int status;
+       DEFINE_WAIT(wait);
+
+       if (count < 4)
+               return 0;
+
+       prepare_to_wait(&err_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (errcnt == 0)
+               schedule();
+       finish_wait(&err_wait_q, &wait);
+       if (signal_pending(current))
+               return -EINTR;
+
+       local_irq_save(flags);
+       status = copy_to_user(buf, &errval, 4);
+       if (status) {
+               local_irq_restore(flags);
+               return -EFAULT;
+       }
+       errcnt = 0;
+       local_irq_restore(flags);
+
+       return 4;
+}
+
+static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &err_wait_q, wait);
+       if (errcnt != 0)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+struct file_operations dsp_err_fops = {
+       .owner = THIS_MODULE,
+       .poll  = dsp_err_poll,
+       .read  = dsp_err_read,
+};
+
+/*
+ * set / clear functions
+ */
+
+/* DSP MMU */
+static void dsp_err_mmu_set(unsigned long arg)
+{
+       disable_irq(omap_dsp->mmu->irq);
+       mmu_fadr = (u32)arg;
+}
+
+static void dsp_err_mmu_clr(void)
+{
+       enable_irq(omap_dsp->mmu->irq);
+}
+
+/* WDT */
+static void dsp_err_wdt_set(unsigned long arg)
+{
+       wdtval = (u16)arg;
+}
+
+/*
+ * error code handler
+ */
+static struct {
+       unsigned long val;
+       void (*set)(unsigned long arg);
+       void (*clr)(void);
+} dsp_err_desc[ERRCODE_MAX] = {
+       [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
+       [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
+};
+
+void dsp_err_set(enum errcode_e code, unsigned long arg)
+{
+       if (dsp_err_desc[code].set != NULL)
+               dsp_err_desc[code].set(arg);
+
+       errval |= dsp_err_desc[code].val;
+       errcnt++;
+       wake_up_interruptible(&err_wait_q);
+}
+
+void dsp_err_clear(enum errcode_e code)
+{
+       errval &= ~dsp_err_desc[code].val;
+
+       if (dsp_err_desc[code].clr != NULL)
+               dsp_err_desc[code].clr();
+}
+
+int dsp_err_isset(enum errcode_e code)
+{
+       return (errval & dsp_err_desc[code].val) ? 1 : 0;
+}
+
+void dsp_err_notify(void)
+{
+       /* new error code should be assigned */
+       dsp_err_set(DSP_ERR_WDT, 0);
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+static void mbox_err_wdt(u16 data)
+{
+       dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+/* v3.3 obsolete */
+void mbox_wdt(struct mbcmd *mb)
+{
+       mbox_err_wdt(mb->data);
+}
+#endif
+
+extern void mbox_err_ipbfull(void);
+extern void mbox_err_fatal(u8 tid);
+
+void mbox_err(struct mbcmd *mb)
+{
+       u8 eid = mb->cmd_l;
+       char *eidnm = subcmd_name(mb);
+       u8 tid;
+
+       if (eidnm) {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
+       } else {
+               printk(KERN_WARNING
+                      "mbox: ERR from DSP (unknown EID=%02x): %04x\n",
+                      eid, mb->data);
+       }
+
+       switch (eid) {
+       case EID_IPBFULL:
+               mbox_err_ipbfull();
+               break;
+
+       case EID_FATAL:
+               tid = mb->data & 0x00ff;
+               mbox_err_fatal(tid);
+               break;
+
+       case EID_WDT:
+               mbox_err_wdt(mb->data);
+               break;
+       }
+}
+
+/*
+ *
+ */
+void dsp_err_start(void)
+{
+       enum errcode_e i;
+
+       for (i = 0; i < ERRCODE_MAX; i++) {
+               if (dsp_err_isset(i))
+                       dsp_err_clear(i);
+       }
+       omap_dsp->mbox->err_notify = dsp_err_notify;
+       errcnt = 0;
+}
+
+void dsp_err_stop(void)
+{
+       wake_up_interruptible(&err_wait_q);
+       omap_dsp->mbox->err_notify = NULL;
+}
diff --git a/drivers/dsp/dspgateway/hardware_dsp.h b/drivers/dsp/dspgateway/hardware_dsp.h
new file mode 100644 (file)
index 0000000..5af46f8
--- /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
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3430)
+#include "omap2_dsp.h"
+#endif
+
+#endif /* __OMAP_DSP_HARDWARE_DSP_H */
diff --git a/drivers/dsp/dspgateway/ipbuf.c b/drivers/dsp/dspgateway/ipbuf.c
new file mode 100644 (file)
index 0000000..b05ba07
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <mach/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+
+static struct ipbuf_head *g_ipbuf;
+struct ipbcfg ipbcfg;
+struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+static struct ipblink ipb_free = IPBLINK_INIT;
+static int ipbuf_sys_hold_mem_active;
+
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
+void ipbuf_stop(void)
+{
+       int i;
+
+       device_remove_file(omap_dsp->dev, &dev_attr_ipbuf);
+
+       spin_lock(&ipb_free.lock);
+       RESET_IPBLINK(&ipb_free);
+       spin_unlock(&ipb_free.lock);
+
+       ipbcfg.ln = 0;
+       if (g_ipbuf) {
+               kfree(g_ipbuf);
+               g_ipbuf = NULL;
+       }
+       for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
+               dsp_mem_disable((void *)daram_base);
+       }
+       ipbuf_sys_hold_mem_active = 0;
+}
+
+int ipbuf_config(u16 ln, u16 lsz, void *base)
+{
+       size_t lsz_byte = ((size_t)lsz) << 1;
+       size_t size;
+       int ret = 0;
+       int i;
+
+       /*
+        * global IPBUF
+        */
+       if (((unsigned long)base) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: global ipbuf address(0x%p) is not "
+                      "32-bit aligned!\n", base);
+               return -EINVAL;
+       }
+       size = lsz_byte * ln;
+       if (dsp_address_validate(base, size, "global ipbuf") < 0)
+               return -EINVAL;
+
+       g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+       if (g_ipbuf == NULL) {
+               printk(KERN_ERR
+                      "omapdsp: memory allocation for ipbuf failed.\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < ln; i++) {
+               void *top, *btm;
+
+               top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
+               btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
+               g_ipbuf[i].p = (struct ipbuf *)top;
+               g_ipbuf[i].bid = i;
+               if (((unsigned long)top & 0xfffe0000) !=
+                   ((unsigned long)btm & 0xfffe0000)) {
+                       /*
+                        * an ipbuf line should not cross
+                        * 64k-word boundary.
+                        */
+                       printk(KERN_ERR
+                              "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
+                              "  @0x%p, size=0x%08x\n", i, top, lsz_byte);
+                       ret = -EINVAL;
+                       goto free_out;
+               }
+       }
+       ipbcfg.ln       = ln;
+       ipbcfg.lsz      = lsz;
+       ipbcfg.base     = base;
+       ipbcfg.bsycnt   = ln;   /* DSP holds all ipbufs initially. */
+       ipbcfg.cnt_full = 0;
+
+       pr_info("omapdsp: IPBUF configuration\n"
+               "           %d words * %d lines at 0x%p.\n",
+               ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_ipbuf);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+
+       return ret;
+
+ free_out:
+       kfree(g_ipbuf);
+       g_ipbuf = NULL;
+       return ret;
+}
+
+int ipbuf_sys_config(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: system ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
+                                "system ipbuf(%s)", dir_str) < 0)
+               return -1;
+       if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
+               printk(KERN_WARNING
+                      "omapdsp: system ipbuf(%s) is placed in"
+                      " DSP internal memory.\n"
+                      "         It will prevent DSP from idling.\n", dir_str);
+               ipbuf_sys_hold_mem_active++;
+               /*
+                * dsp_mem_enable() never fails because
+                * it has been already enabled in dspcfg process and
+                * this will just increment the usecount.
+                */
+               dsp_mem_enable((void *)daram_base);
+       }
+
+       if (dir == DIR_D2A)
+               ipbuf_sys_da = p;
+       else
+               ipbuf_sys_ad = p;
+
+       return 0;
+}
+
+int ipbuf_p_validate(void *p, arm_dsp_dir_t dir)
+{
+       char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
+
+       if (((unsigned long)p) & 0x3) {
+               printk(KERN_ERR
+                      "omapdsp: private ipbuf(%s) address(0x%p) is "
+                      "not 32-bit aligned!\n", dir_str, p);
+               return -1;
+       }
+       return dsp_address_validate(p, sizeof(struct ipbuf_p),
+                                   "private ipbuf(%s)", dir_str);
+}
+
+/*
+ * Global IPBUF operations
+ */
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
+{
+       return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+       struct ipbuf_head *ipb_h;
+
+       if (dsp_mem_enable_ipbuf() < 0)
+               return NULL;
+
+       spin_lock(&ipb_free.lock);
+
+       if (ipblink_empty(&ipb_free)) {
+               /* FIXME: wait on queue when not available.  */
+               ipb_h = NULL;
+               goto out;
+       }
+       ipb_h = &g_ipbuf[ipb_free.top];
+       ipb_h->p->la = tid;     /* lock */
+       __ipblink_del_top(&ipb_free);
+out:
+       spin_unlock(&ipb_free.lock);
+       dsp_mem_disable_ipbuf();
+
+       return ipb_h;
+}
+
+void release_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipb_h->p->la == TID_FREE) {
+               printk(KERN_WARNING
+                      "omapdsp: attempt to release unlocked IPBUF[%d].\n",
+                      ipb_h->bid);
+               /*
+                * FIXME: re-calc bsycnt
+                */
+               return;
+       }
+       ipb_h->p->la = TID_FREE;
+       ipb_h->p->sa = TID_FREE;
+       ipblink_add_tail(&ipb_free, ipb_h->bid);
+}
+
+static int try_yld(struct ipbuf_head *ipb_h)
+{
+       int status;
+
+       ipb_h->p->sa = TID_ANON;
+       status = mbcompose_send(BKYLD, 0, ipb_h->bid);
+       if (status < 0) {
+               /* DSP is busy and ARM keeps this line. */
+               release_ipbuf(ipb_h);
+               return status;
+       }
+
+       ipb_bsycnt_inc(&ipbcfg);
+       return 0;
+}
+
+/*
+ * balancing ipbuf lines with DSP
+ */
+static void do_balance_ipbuf(struct work_struct *unused)
+{
+       while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
+               struct ipbuf_head *ipb_h;
+
+               if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
+                       return;
+               if (try_yld(ipb_h) < 0)
+                       return;
+       }
+}
+
+static DECLARE_WORK(balance_ipbuf_work, do_balance_ipbuf);
+
+void balance_ipbuf(void)
+{
+       schedule_work(&balance_ipbuf_work);
+}
+
+/* for process context */
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
+{
+       if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
+               /* we don't have enough IPBUF lines. let's keep it. */
+               release_ipbuf(ipb_h);
+       } else {
+               /* we have enough IPBUF lines. let's return this line to DSP. */
+               ipb_h->p->la = TID_ANON;
+               try_yld(ipb_h);
+               balance_ipbuf();
+       }
+}
+
+/* for interrupt context */
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
+{
+       release_ipbuf(ipb_h);
+       balance_ipbuf();
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+
+void mbox_err_ipbfull(void)
+{
+       ipbcfg.cnt_full++;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       u16 bid;
+
+       for (bid = 0; bid < ipbcfg.ln; bid++) {
+               struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+               u16 la = ipb_h->p->la;
+               u16 ld = ipb_h->p->ld;
+               u16 c  = ipb_h->p->c;
+
+               if (len > PAGE_SIZE - 100) {
+                       len += sprintf(buf + len, "out of buffer.\n");
+                       goto finish;
+               }
+
+               len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
+                              bid, ipb_h->p);
+               if (la == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(already read and now free for Linux)\n",
+                                      ld);
+               } else if (ld == TID_FREE) {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(already read and now free for DSP)\n",
+                                      la);
+               } else if (ipbuf_is_held(ld, bid)) {
+                       len += sprintf(buf + len,
+                                      "  DSPtask[%d]->Linux "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", ld, c);
+               } else {
+                       len += sprintf(buf + len,
+                                      "  Linux->DSPtask[%d] "
+                                      "(waiting to be read)\n"
+                                      "  count = %d\n", la, c);
+               }
+       }
+
+       len += sprintf(buf + len, "\nFree IPBUF link: ");
+       spin_lock(&ipb_free.lock);
+       ipblink_for_each(bid, &ipb_free) {
+               len += sprintf(buf + len, "%d ", bid);
+       }
+       spin_unlock(&ipb_free.lock);
+       len += sprintf(buf + len, "\n");
+       len += sprintf(buf + len, "IPBFULL error count: %ld\n",
+                      ipbcfg.cnt_full);
+
+finish:
+       return len;
+}
diff --git a/drivers/dsp/dspgateway/ipbuf.h b/drivers/dsp/dspgateway/ipbuf.h
new file mode 100644 (file)
index 0000000..926d353
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_IPBUF_H
+#define __PLAT_OMAP_DSP_IPBUF_H
+
+struct ipbuf {
+       u16 c;                  /* count */
+       u16 next;               /* link */
+       u16 la;                 /* lock owner (ARM side) */
+       u16 sa;                 /* sync word (ARM->DSP) */
+       u16 ld;                 /* lock owner (DSP side) */
+       u16 sd;                 /* sync word (DSP->ARM) */
+       unsigned char d[0];     /* data */
+};
+
+struct ipbuf_p {
+       u16 c;          /* count */
+       u16 s;          /* sync word */
+       u16 al;         /* data address lower */
+       u16 ah;         /* data address upper */
+};
+
+#define IPBUF_SYS_DLEN 31
+
+struct ipbuf_sys {
+       u16 s;                  /* sync word */
+       u16 d[IPBUF_SYS_DLEN];  /* data */
+};
+
+struct ipbcfg {
+       u16 ln;
+       u16 lsz;
+       void *base;
+       u16 bsycnt;
+       unsigned long cnt_full; /* count of IPBFULL error */
+};
+
+struct ipbuf_head {
+       u16 bid;
+       struct ipbuf *p;
+};
+
+extern struct ipbcfg ipbcfg;
+extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
+
+#define ipb_bsycnt_inc(ipbcfg) atomic_inc((atomic_t *)&((ipbcfg)->bsycnt))
+#define ipb_bsycnt_dec(ipbcfg) atomic_dec((atomic_t *)&((ipbcfg)->bsycnt))
+
+#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
+#define dsp_mem_disable_ipbuf()        dsp_mem_disable(ipbcfg.base)
+
+struct ipblink {
+       spinlock_t lock;
+       u16 top;
+       u16 tail;
+};
+
+#define IPBLINK_INIT {                         \
+               .lock = SPIN_LOCK_UNLOCKED,     \
+               .top  = BID_NULL,               \
+               .tail = BID_NULL,               \
+       }
+
+#define INIT_IPBLINK(link)                     \
+       do {                                    \
+               spin_lock_init(&(link)->lock);  \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define RESET_IPBLINK(link)                    \
+       do {                                    \
+               (link)->top  = BID_NULL;        \
+               (link)->tail = BID_NULL;        \
+       } while(0)
+
+#define ipblink_empty(link)    ((link)->top == BID_NULL)
+
+static inline void __ipblink_del_top(struct ipblink *link)
+{
+       struct ipbuf_head *ipb_h = bid_to_ipbuf(link->top);
+
+       if ((link->top = ipb_h->p->next) == BID_NULL)
+               link->tail = BID_NULL;
+       else
+               ipb_h->p->next = BID_NULL;
+}
+
+static inline void ipblink_del_top(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_top(link);
+       spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       if (ipblink_empty(link))
+               link->top = bid;
+       else
+               bid_to_ipbuf(link->tail)->p->next = bid;
+       link->tail = bid;
+}
+
+static inline void ipblink_add_tail(struct ipblink *link, u16 bid)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_tail(link, bid);
+       spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush(struct ipblink *link)
+{
+       u16 bid;
+
+       while (!ipblink_empty(link)) {
+               bid = link->top;
+               __ipblink_del_top(link);
+               unuse_ipbuf(bid_to_ipbuf(bid));
+       }
+}
+
+static inline void ipblink_flush(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush(link);
+       spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_add_pvt(struct ipblink *link)
+{
+       link->top  = BID_PVT;
+       link->tail = BID_PVT;
+}
+
+static inline void ipblink_add_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_add_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_del_pvt(struct ipblink *link)
+{
+       link->top  = BID_NULL;
+       link->tail = BID_NULL;
+}
+
+static inline void ipblink_del_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_del_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+static inline void __ipblink_flush_pvt(struct ipblink *link)
+{
+       if (!ipblink_empty(link))
+               ipblink_del_pvt(link);
+}
+
+static inline void ipblink_flush_pvt(struct ipblink *link)
+{
+       spin_lock(&link->lock);
+       __ipblink_flush_pvt(link);
+       spin_unlock(&link->lock);
+}
+
+#define ipblink_for_each(bid, link) \
+       for (bid = (link)->top; bid != BID_NULL; bid = bid_to_ipbuf(bid)->p->next)
+
+#endif /* __PLAT_OMAP_DSP_IPBUF_H */
diff --git a/drivers/dsp/dspgateway/mblog.c b/drivers/dsp/dspgateway/mblog.c
new file mode 100644 (file)
index 0000000..7e008af
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2003-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <mach/mailbox.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+char *subcmd_name(struct mbcmd *mb)
+{
+       u8 cmd_h = mb->cmd_h;
+       u8 cmd_l = mb->cmd_l;
+       char *s;
+
+       switch (cmd_h) {
+       case MBOX_CMD_DSP_RUNLEVEL:
+               s = (cmd_l == RUNLEVEL_USER)     ? "USER":
+                   (cmd_l == RUNLEVEL_SUPER)    ? "SUPER":
+                   (cmd_l == RUNLEVEL_RECOVERY) ? "RECOVERY":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_PM:
+               s = (cmd_l == PM_DISABLE) ? "DISABLE":
+                   (cmd_l == PM_ENABLE)  ? "ENABLE":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_KFUNC:
+               s = (cmd_l == KFUNC_FBCTL) ? "FBCTL":
+                       (cmd_l == KFUNC_POWER) ?
+                       ((mb->data == AUDIO_PWR_UP)     ? "PWR AUD /UP":
+                        (mb->data == AUDIO_PWR_DOWN)   ? "PWR AUD /DOWN":
+                        (mb->data == AUDIO_PWR_DOWN2)  ? "PWR AUD /DOWN(2)":
+                        (mb->data == DSP_PWR_UP)       ? "PWR DSP /UP":
+                        (mb->data == DSP_PWR_DOWN)     ? "PWR DSP /DOWN":
+                        (mb->data == DVFS_START)       ? "PWR DVFS/START":
+                        (mb->data == DVFS_STOP)        ? "PWR DVFS/STOP":
+                        NULL):
+
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_DSPCFG:
+               {
+                       u8 cfgc = cmd_l & 0x7f;
+                       s = (cfgc == DSPCFG_REQ)     ? "REQ":
+                           (cfgc == DSPCFG_SYSADRH) ? "SYSADRH":
+                           (cfgc == DSPCFG_SYSADRL) ? "SYSADRL":
+                           (cfgc == DSPCFG_ABORT)   ? "ABORT":
+                           (cfgc == DSPCFG_PROTREV) ? "PROTREV":
+                           NULL;
+                       break;
+               }
+       case MBOX_CMD_DSP_REGRW:
+               s = (cmd_l == REGRW_MEMR) ? "MEMR":
+                   (cmd_l == REGRW_MEMW) ? "MEMW":
+                   (cmd_l == REGRW_IOR)  ? "IOR":
+                   (cmd_l == REGRW_IOW)  ? "IOW":
+                   (cmd_l == REGRW_DATA) ? "DATA":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_GETVAR:
+       case MBOX_CMD_DSP_SETVAR:
+               s = (cmd_l == VARID_ICRMASK)  ? "ICRMASK":
+                   (cmd_l == VARID_LOADINFO) ? "LOADINFO":
+                   NULL;
+               break;
+       case MBOX_CMD_DSP_ERR:
+               s = (cmd_l == EID_BADTID)     ? "BADTID":
+                   (cmd_l == EID_BADTCN)     ? "BADTCN":
+                   (cmd_l == EID_BADBID)     ? "BADBID":
+                   (cmd_l == EID_BADCNT)     ? "BADCNT":
+                   (cmd_l == EID_NOTLOCKED)  ? "NOTLOCKED":
+                   (cmd_l == EID_STVBUF)     ? "STVBUF":
+                   (cmd_l == EID_BADADR)     ? "BADADR":
+                   (cmd_l == EID_BADTCTL)    ? "BADTCTL":
+                   (cmd_l == EID_BADPARAM)   ? "BADPARAM":
+                   (cmd_l == EID_FATAL)      ? "FATAL":
+                   (cmd_l == EID_WDT)        ? "WDT":
+                   (cmd_l == EID_NOMEM)      ? "NOMEM":
+                   (cmd_l == EID_NORES)      ? "NORES":
+                   (cmd_l == EID_IPBFULL)    ? "IPBFULL":
+                   (cmd_l == EID_TASKNOTRDY) ? "TASKNOTRDY":
+                   (cmd_l == EID_TASKBSY)    ? "TASKBSY":
+                   (cmd_l == EID_TASKERR)    ? "TASKERR":
+                   (cmd_l == EID_BADCFGTYP)  ? "BADCFGTYP":
+                   (cmd_l == EID_DEBUG)      ? "DEBUG":
+                   (cmd_l == EID_BADSEQ)     ? "BADSEQ":
+                   (cmd_l == EID_BADCMD)     ? "BADCMD":
+                   NULL;
+               break;
+       default:
+               s = NULL;
+       }
+
+       return s;
+}
+
+/* output of show() method should fit to PAGE_SIZE */
+#define MBLOG_DEPTH    64
+
+struct mblogent {
+       unsigned long jiffies;
+       mbox_msg_t msg;
+       arm_dsp_dir_t dir;
+};
+
+static struct {
+       spinlock_t lock;
+       int wp;
+       unsigned long cnt, cnt_ad, cnt_da;
+       struct mblogent ent[MBLOG_DEPTH];
+} mblog = {
+       .lock = SPIN_LOCK_UNLOCKED,
+};
+
+#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
+       char *dir_str;
+       char *subname;
+
+       dir_str = (dir == DIR_A2D) ? "sending  " : "receiving";
+       switch (ci->cmd_l_type) {
+       case CMD_L_TYPE_SUBCMD:
+               subname = subcmd_name(mb);
+               if (unlikely(!subname))
+                       subname = "Unknown";
+               pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n",
+                        dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                        ci->name, subname, mb->data);
+               break;
+       case CMD_L_TYPE_TID:
+               pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n",
+                        dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                        ci->name, mb->cmd_l, mb->data);
+               break;
+       case CMD_L_TYPE_NULL:
+               pr_debug("mbox: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n",
+                        dir_str, mb->seq, mb->cmd_h, mb->cmd_l,
+                        ci->name, mb->data);
+               break;
+       }
+}
+#else
+static inline void mblog_print_cmd(struct mbcmd *mb, arm_dsp_dir_t dir) { }
+#endif
+
+void mblog_add(struct mbcmd *mb, arm_dsp_dir_t dir)
+{
+       struct mblogent *ent;
+
+       spin_lock(&mblog.lock);
+       ent = &mblog.ent[mblog.wp];
+       ent->jiffies = jiffies;
+       ent->msg = *(mbox_msg_t *)mb;
+       ent->dir = dir;
+       if (mblog.cnt < 0xffffffff)
+               mblog.cnt++;
+       switch (dir) {
+       case DIR_A2D:
+               if (mblog.cnt_ad < 0xffffffff)
+                       mblog.cnt_ad++;
+               break;
+       case DIR_D2A:
+               if (mblog.cnt_da < 0xffffffff)
+                       mblog.cnt_da++;
+               break;
+       }
+       if (++mblog.wp == MBLOG_DEPTH)
+               mblog.wp = 0;
+       spin_unlock(&mblog.lock);
+
+       mblog_print_cmd(mb, dir);
+}
+
+/*
+ * sysfs file
+ */
+static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
+{
+       int len = 0;
+       int wp;
+       int i;
+
+       spin_lock(&mblog.lock);
+
+       wp = mblog.wp;
+       len += sprintf(buf + len,
+                      "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n",
+                      mblog.cnt, mblog.cnt_ad, mblog.cnt_da);
+       if (mblog.cnt == 0)
+               goto done;
+
+       len += sprintf(buf + len, "           ARM->DSP   ARM<-DSP\n");
+       len += sprintf(buf + len, " jiffies  cmd  data  cmd  data\n");
+       i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0;
+       do {
+               struct mblogent *ent = &mblog.ent[i];
+               struct mbcmd *mb = (struct mbcmd *)&ent->msg;
+               char *subname;
+               struct cmdinfo ci_null = {
+                       .name = "Unknown",
+                       .cmd_l_type = CMD_L_TYPE_NULL,
+               };
+               const struct cmdinfo *ci;
+
+               len += sprintf(buf + len,
+                              (ent->dir == DIR_A2D) ?
+                               "%08lx  %04x %04x            ":
+                               "%08lx             %04x %04x ",
+                              ent->jiffies,
+                              (ent->msg >> 16) & 0x7fff, ent->msg & 0xffff);
+
+               if ((ci = cmdinfo[mb->cmd_h]) == NULL)
+                       ci = &ci_null;
+
+               switch (ci->cmd_l_type) {
+               case CMD_L_TYPE_SUBCMD:
+                       if ((subname = subcmd_name(mb)) == NULL)
+                               subname = "Unknown";
+                       len += sprintf(buf + len, "%s:%s\n",
+                                      ci->name, subname);
+                       break;
+               case CMD_L_TYPE_TID:
+                       len += sprintf(buf + len, "%s:task %d\n",
+                                      ci->name, mb->cmd_l);
+                       break;
+               case CMD_L_TYPE_NULL:
+                       len += sprintf(buf + len, "%s\n", ci->name);
+                       break;
+               }
+
+               if (++i == MBLOG_DEPTH)
+                       i = 0;
+       } while (i != wp);
+
+done:
+       spin_unlock(&mblog.lock);
+
+       return len;
+}
+
+static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
+
+void __init mblog_init(void)
+{
+       int ret;
+
+       ret = device_create_file(omap_dsp->dev, &dev_attr_mblog);
+       if (ret)
+               printk(KERN_ERR "device_create_file failed: %d\n", ret);
+}
+
+void mblog_exit(void)
+{
+       device_remove_file(omap_dsp->dev, &dev_attr_mblog);
+}
diff --git a/drivers/dsp/dspgateway/mmu.h b/drivers/dsp/dspgateway/mmu.h
new file mode 100644 (file)
index 0000000..9d60e9e
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef __PLAT_OMAP_DSP_MMU_H
+#define __PLAT_OMAP_DSP_MMU_H
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#ifdef CONFIG_ARCH_OMAP15XX
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = IO_ADDRESS(OMAP1510_DSP_MMU_BASE),
+       .membase        = OMAP1510_DSP_BASE,
+       .memsize        = OMAP1510_DSP_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_1510_DSP_MMU,
+       .ops            = &omap1_mmu_ops,
+};
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = IO_ADDRESS(OMAP16XX_DSP_MMU_BASE),
+       .membase        = OMAP16XX_DSP_BASE,
+       .memsize        = OMAP16XX_DSP_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_1610_DSP_MMU,
+       .ops            = &omap1_mmu_ops,
+};
+#endif
+#else /* OMAP2 */
+struct omap_mmu dsp_mmu = {
+       .name           = "mmu:dsp",
+       .type           = OMAP_MMU_DSP,
+       .base           = DSP_MMU_24XX_VIRT,
+       .membase        = DSP_MEM_24XX_VIRT,
+       .memsize        = DSP_MEM_24XX_SIZE,
+       .nr_tlb_entries = 32,
+       .addrspace      = 24,
+       .irq            = INT_24XX_DSP_MMU,
+       .ops            = &omap2_mmu_ops,
+};
+
+#define IOMAP_VAL      0x3f
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+static struct omapfb_notifier_block *omapfb_nb;
+static int omapfb_ready;
+#endif
+
+/*
+ * OMAP1 EMIFF access
+ */
+#ifdef CONFIG_ARCH_OMAP1
+#define EMIF_PRIO_LB_MASK      0x0000f000
+#define EMIF_PRIO_LB_SHIFT     12
+#define EMIF_PRIO_DMA_MASK     0x00000f00
+#define EMIF_PRIO_DMA_SHIFT    8
+#define EMIF_PRIO_DSP_MASK     0x00000070
+#define EMIF_PRIO_DSP_SHIFT    4
+#define EMIF_PRIO_MPU_MASK     0x00000007
+#define EMIF_PRIO_MPU_SHIFT    0
+#define set_emiff_dma_prio(prio) \
+       do { \
+               omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \
+                            ~EMIF_PRIO_DMA_MASK) | \
+                           ((prio) << EMIF_PRIO_DMA_SHIFT), \
+                           OMAP_TC_OCPT1_PRIOR); \
+       } while(0)
+#else
+#define set_emiff_dma_prio(prio)       do { } while (0)
+#endif /* CONFIG_ARCH_OMAP1 */
+
+#ifdef CONFIG_ARCH_OMAP1
+static int dsp_mmu_itack(void)
+{
+       unsigned long dspadr;
+
+       pr_info("omapdsp: sending DSP MMU interrupt ack.\n");
+       if (!dsp_err_isset(ERRCODE_MMU)) {
+               printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n");
+               return -EINVAL;
+       }
+       dspadr = dsp_mmu.fault_address & ~(SZ_4K-1);
+       /* FIXME: reserve TLB entry for this */
+       omap_mmu_exmap(&dsp_mmu, dspadr, 0, SZ_4K, EXMAP_TYPE_MEM);
+       pr_info("omapdsp: falling into recovery runlevel...\n");
+       dsp_set_runlevel(RUNLEVEL_RECOVERY);
+       omap_mmu_itack(&dsp_mmu);
+       udelay(100);
+       omap_mmu_exunmap(&dsp_mmu, dspadr);
+       dsp_err_clear(ERRCODE_MMU);
+       return 0;
+}
+
+/*
+ * intmem_enable() / disable():
+ * if the address is in DSP internal memories,
+ * we send PM mailbox commands so that DSP DMA domain won't go in idle
+ * when ARM is accessing to those memories.
+ */
+static int intmem_enable(void)
+{
+       int ret = 0;
+
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               ret = mbcompose_send(PM, PM_ENABLE, DSPREG_ICR_DMA);
+
+       return ret;
+}
+
+static void intmem_disable(void) {
+       if (dsp_cfgstat_get_stat() == CFGSTAT_READY)
+               mbcompose_send(PM, PM_DISABLE, DSPREG_ICR_DMA);
+}
+#else
+static int intmem_enable(void) { return 0; }
+static void intmem_disable(void) { }
+static int dsp_mmu_itack(void) { return 0; }
+#endif
+
+#ifdef CONFIG_ARCH_OMAP2
+static inline void dsp_mem_ipi_init(void)
+{
+       int i, dspmem_pg_count;
+       dspmem_pg_count = dspmem_size >> 12;
+       for (i = 0; i < dspmem_pg_count; i++) {
+               writel(i, DSP_IPI_INDEX);
+               writel(DSP_IPI_ENTRY_ELMSIZEVALUE_16, DSP_IPI_ENTRY);
+       }
+       writel(1, DSP_IPI_ENABLE);
+       writel(IOMAP_VAL, DSP_IPI_IOMAP);
+}
+#else
+static inline void dsp_mem_ipi_init(void) { }
+#endif
+
+#endif /* __PLAT_OMAP_DSP_MMU_H */
diff --git a/drivers/dsp/dspgateway/omap1_dsp.h b/drivers/dsp/dspgateway/omap1_dsp.h
new file mode 100644 (file)
index 0000000..f4ec73e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP1_DSP_H
+#define __OMAP_DSP_OMAP1_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP15XX
+#define OMAP1510_DARAM_BASE    (OMAP1510_DSP_BASE + 0x0)
+#define OMAP1510_DARAM_SIZE    0x10000
+#define OMAP1510_SARAM_BASE    (OMAP1510_DSP_BASE + 0x10000)
+#define OMAP1510_SARAM_SIZE    0x18000
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+#define OMAP16XX_DARAM_BASE    (OMAP16XX_DSP_BASE + 0x0)
+#define OMAP16XX_DARAM_SIZE    0x10000
+#define OMAP16XX_SARAM_BASE    (OMAP16XX_DSP_BASE + 0x10000)
+#define OMAP16XX_SARAM_SIZE    0x18000
+#endif
+
+/*
+ * Reset Control
+ */
+#define ARM_RSTCT1_SW_RST              0x0008
+#define ARM_RSTCT1_DSP_RST             0x0004
+#define ARM_RSTCT1_DSP_EN              0x0002
+#define ARM_RSTCT1_ARM_RST             0x0001
+
+/*
+ * MPUI
+ */
+#define MPUI_CTRL_WORDSWAP_MASK                0x00600000
+#define MPUI_CTRL_WORDSWAP_ALL         0x00000000
+#define MPUI_CTRL_WORDSWAP_NONAPI      0x00200000
+#define MPUI_CTRL_WORDSWAP_API         0x00400000
+#define MPUI_CTRL_WORDSWAP_NONE                0x00600000
+#define MPUI_CTRL_AP_MASK              0x001c0000
+#define MPUI_CTRL_AP_MDH               0x00000000
+#define MPUI_CTRL_AP_MHD               0x00040000
+#define MPUI_CTRL_AP_DMH               0x00080000
+#define MPUI_CTRL_AP_HMD               0x000c0000
+#define MPUI_CTRL_AP_DHM               0x00100000
+#define MPUI_CTRL_AP_HDM               0x00140000
+#define MPUI_CTRL_BYTESWAP_MASK                0x00030000
+#define MPUI_CTRL_BYTESWAP_NONE                0x00000000
+#define MPUI_CTRL_BYTESWAP_NONAPI      0x00010000
+#define MPUI_CTRL_BYTESWAP_ALL         0x00020000
+#define MPUI_CTRL_BYTESWAP_API         0x00030000
+#define MPUI_CTRL_TIMEOUT_MASK         0x0000ff00
+#define MPUI_CTRL_APIF_HNSTB_DIV_MASK  0x000000f0
+#define MPUI_CTRL_S_NABORT_GL          0x00000008
+#define MPUI_CTRL_S_NABORT_32BIT       0x00000004
+#define MPUI_CTRL_EN_TIMEOUT           0x00000002
+#define MPUI_CTRL_HF_MCUCLK            0x00000001
+#define DSP_BOOT_CONFIG_DIRECT         0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT     0x00000001
+#define DSP_BOOT_CONFIG_IDLE           0x00000002
+#define DSP_BOOT_CONFIG_DL16           0x00000003
+#define DSP_BOOT_CONFIG_DL32           0x00000004
+#define DSP_BOOT_CONFIG_MPUI           0x00000005
+#define DSP_BOOT_CONFIG_INTERNAL       0x00000006
+
+/*
+ * DSP boot mode
+ *   direct:        0xffff00
+ *   pseudo direct: 0x080000
+ *   MPUI:          branch 0x010000
+ *   internel:      branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT            0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT                0x080000
+#define DSP_BOOT_ADR_MPUI              0x010000
+#define DSP_BOOT_ADR_INTERNAL          0x024000
+
+/*
+ * TC
+ */
+#define TC_ENDIANISM_SWAP              0x00000002
+#define TC_ENDIANISM_SWAP_WORD         0x00000002
+#define TC_ENDIANISM_SWAP_BYTE         0x00000000
+#define TC_ENDIANISM_EN                        0x00000001
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS       0xffc0
+#define DSPREG_ICR_EMIF                        0x0020
+#define DSPREG_ICR_DPLL                        0x0010
+#define DSPREG_ICR_PER                 0x0008
+#define DSPREG_ICR_CACHE               0x0004
+#define DSPREG_ICR_DMA                 0x0002
+#define DSPREG_ICR_CPU                 0x0001
+
+#endif /* __OMAP_DSP_OMAP1_DSP_H */
diff --git a/drivers/dsp/dspgateway/omap2_dsp.h b/drivers/dsp/dspgateway/omap2_dsp.h
new file mode 100644 (file)
index 0000000..4ac5180
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_DSP_OMAP2_DSP_H
+#define __OMAP_DSP_OMAP2_DSP_H
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP24XX_DARAM_BASE    (DSP_MEM_24XX_VIRT + 0x0)
+#define OMAP24XX_DARAM_SIZE    0x10000
+#define OMAP24XX_SARAM_BASE    (DSP_MEM_24XX_VIRT + 0x10000)
+#define OMAP24XX_SARAM_SIZE    0x18000
+#endif
+
+#include <mach/hardware.h>
+
+/*
+ * DSP IPI registers: mapped to 0xe1000000 -- use readX(), writeX()
+ */
+#ifdef CONFIG_ARCH_OMAP24XX
+#define DSP_IPI_BASE                   DSP_IPI_24XX_VIRT
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+#define DSP_IPI_BASE                   DSP_IPI_34XX_VIRT
+#endif
+
+#define DSP_IPI_REVISION               (DSP_IPI_BASE + 0x00)
+#define DSP_IPI_SYSCONFIG              (DSP_IPI_BASE + 0x10)
+#define DSP_IPI_INDEX                  (DSP_IPI_BASE + 0x40)
+#define DSP_IPI_ENTRY                  (DSP_IPI_BASE + 0x44)
+#define DSP_IPI_ENABLE                 (DSP_IPI_BASE + 0x48)
+#define DSP_IPI_IOMAP                  (DSP_IPI_BASE + 0x4c)
+#define DSP_IPI_DSPBOOTCONFIG          (DSP_IPI_BASE + 0x50)
+
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_MASK        0x00000003
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_8   0x00000000
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_16  0x00000001
+#define DSP_IPI_ENTRY_ELMSIZEVALUE_32  0x00000002
+
+#define DSP_BOOT_CONFIG_DIRECT         0x00000000
+#define DSP_BOOT_CONFIG_PSD_DIRECT     0x00000001
+#define DSP_BOOT_CONFIG_IDLE           0x00000002
+#define DSP_BOOT_CONFIG_DL16           0x00000003
+#define DSP_BOOT_CONFIG_DL32           0x00000004
+#define DSP_BOOT_CONFIG_API            0x00000005
+#define DSP_BOOT_CONFIG_INTERNAL       0x00000006
+
+/*
+ * DSP boot mode
+ *   direct:        0xffff00
+ *   pseudo direct: 0x080000
+ *   API:           branch 0x010000
+ *   internel:      branch 0x024000
+ */
+#define DSP_BOOT_ADR_DIRECT            0xffff00
+#define DSP_BOOT_ADR_PSD_DIRECT                0x080000
+#define DSP_BOOT_ADR_API               0x010000
+#define DSP_BOOT_ADR_INTERNAL          0x024000
+
+/*
+ * DSP ICR
+ */
+#define DSPREG_ICR_RESERVED_BITS       0xfc00
+#define DSPREG_ICR_HWA                 0x0200
+#define DSPREG_ICR_IPORT               0x0100
+#define DSPREG_ICR_MPORT               0x0080
+#define DSPREG_ICR_XPORT               0x0040
+#define DSPREG_ICR_DPORT               0x0020
+#define DSPREG_ICR_DPLL                        0x0010
+#define DSPREG_ICR_PER                 0x0008
+#define DSPREG_ICR_CACHE               0x0004
+#define DSPREG_ICR_DMA                 0x0002
+#define DSPREG_ICR_CPU                 0x0001
+
+#endif /* __OMAP_DSP_OMAP2_DSP_H */
diff --git a/drivers/dsp/dspgateway/proclist.h b/drivers/dsp/dspgateway/proclist.h
new file mode 100644 (file)
index 0000000..666ca4d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __PLAT_OMAP_DSP_PROCLIST_H
+#define __PLAT_OMAP_DSP_PROCLIST_H
+
+struct proc_list {
+       struct list_head list_head;
+       pid_t pid;
+       struct file *file;
+};
+
+static inline int proc_list_add(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *new;
+
+       new = kmalloc(sizeof(struct proc_list), GFP_KERNEL);
+       if (new == NULL)
+               return -ENOMEM;
+       new->pid = tsk->pid;
+       new->file = file;
+       spin_lock(lock);
+       list_add_tail(&new->list_head, list);
+       spin_unlock(lock);
+
+       return 0;
+}
+
+static inline void proc_list_del(spinlock_t *lock, struct list_head *list,
+                                    struct task_struct *tsk, struct file *file)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       list_for_each_entry(pl, list, list_head) {
+               if (pl->file == file) {
+                       list_del(&pl->list_head);
+                       kfree(pl);
+                       spin_unlock(lock);
+                       return;
+               }
+       }
+
+       /* correspinding file struct isn't found in the list ???  */
+       printk(KERN_ERR "proc_list_del(): proc_list is inconsistent!\n"
+                       "struct file (%p) not found\n", file);
+       printk(KERN_ERR "listing proc_list...\n");
+       list_for_each_entry(pl, list, list_head)
+               printk(KERN_ERR "  pid:%d file:%p\n", pl->pid, pl->file);
+       spin_unlock(lock);
+}
+
+static inline void proc_list_flush(spinlock_t *lock, struct list_head *list)
+{
+       struct proc_list *pl;
+
+       spin_lock(lock);
+       while (!list_empty(list)) {
+               pl = list_entry(list->next, struct proc_list, list_head);
+               list_del(&pl->list_head);
+               kfree(pl);
+       }
+       spin_unlock(lock);
+}
+
+#endif /* __PLAT_OMAP_DSP_PROCLIST_H */
diff --git a/drivers/dsp/dspgateway/task.c b/drivers/dsp/dspgateway/task.c
new file mode 100644 (file)
index 0000000..a371911
--- /dev/null
@@ -0,0 +1,3041 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <mach/mailbox.h>
+#include <mach/dsp.h>
+#include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+#include "ipbuf.h"
+#include "proclist.h"
+
+/*
+ * devstate: task device state machine
+ * NOTASK:     task is not attached.
+ * ATTACHED:   task is attached.
+ * GARBAGE:    task is detached. waiting for all processes to close this device.
+ * ADDREQ:     requesting for tadd
+ * DELREQ:     requesting for tdel. no process is opening this device.
+ * FREEZED:    task is attached, but reserved to be killed.
+ * ADDFAIL:    tadd failed.
+ * ADDING:     tadd in process.
+ * DELING:     tdel in process.
+ * KILLING:    tkill in process.
+ */
+#define TASKDEV_ST_NOTASK      0x00000001
+#define TASKDEV_ST_ATTACHED    0x00000002
+#define TASKDEV_ST_GARBAGE     0x00000004
+#define TASKDEV_ST_INVALID     0x00000008
+#define TASKDEV_ST_ADDREQ      0x00000100
+#define TASKDEV_ST_DELREQ      0x00000200
+#define TASKDEV_ST_FREEZED     0x00000400
+#define TASKDEV_ST_ADDFAIL     0x00001000
+#define TASKDEV_ST_ADDING      0x00010000
+#define TASKDEV_ST_DELING      0x00020000
+#define TASKDEV_ST_KILLING     0x00040000
+#define TASKDEV_ST_STATE_MASK  0x7fffffff
+#define TASKDEV_ST_STALE       0x80000000
+
+static struct {
+       long state;
+       char *name;
+} devstate_desc[] = {
+       { TASKDEV_ST_NOTASK,   "notask" },
+       { TASKDEV_ST_ATTACHED, "attached" },
+       { TASKDEV_ST_GARBAGE,  "garbage" },
+       { TASKDEV_ST_INVALID,  "invalid" },
+       { TASKDEV_ST_ADDREQ,   "addreq" },
+       { TASKDEV_ST_DELREQ,   "delreq" },
+       { TASKDEV_ST_FREEZED,  "freezed" },
+       { TASKDEV_ST_ADDFAIL,  "addfail" },
+       { TASKDEV_ST_ADDING,   "adding" },
+       { TASKDEV_ST_DELING,   "deling" },
+       { TASKDEV_ST_KILLING,  "killing" },
+};
+
+static char *devstate_name(long state)
+{
+       int i;
+       int max = ARRAY_SIZE(devstate_desc);
+
+       for (i = 0; i < max; i++) {
+               if (state & devstate_desc[i].state)
+                       return devstate_desc[i].name;
+       }
+       return "unknown";
+}
+
+struct rcvdt_bk_struct {
+       struct ipblink link;
+       unsigned int rp;
+};
+
+struct taskdev {
+       struct bus_type *bus;
+       struct device dev;      /* Generic device interface */
+
+       long state;
+       struct rw_semaphore state_sem;
+       wait_queue_head_t state_wait_q;
+       struct mutex usecount_lock;
+       unsigned int usecount;
+       char name[TNM_LEN];
+       struct file_operations fops;
+       spinlock_t proc_list_lock;
+       struct list_head proc_list;
+       struct dsptask *task;
+
+       /* read stuff */
+       wait_queue_head_t read_wait_q;
+       struct mutex read_mutex;
+       spinlock_t read_lock;
+       union {
+               struct kfifo *fifo;     /* for active word */
+               struct rcvdt_bk_struct bk;
+       } rcvdt;
+
+       /* write stuff */
+       wait_queue_head_t write_wait_q;
+       struct mutex write_mutex;
+       spinlock_t wsz_lock;
+       size_t wsz;
+
+       /* tctl stuff */
+       wait_queue_head_t tctl_wait_q;
+       struct mutex tctl_mutex;
+       int tctl_stat;
+       int tctl_ret;   /* return value for tctl_show() */
+
+       /* device lock */
+       struct mutex lock;
+       pid_t lock_pid;
+};
+
+#define to_taskdev(n) container_of(n, struct taskdev, dev)
+
+struct dsptask {
+       enum {
+               TASK_ST_ERR = 0,
+               TASK_ST_READY,
+               TASK_ST_CFGREQ
+       } state;
+       u8 tid;
+       char name[TNM_LEN];
+       u16 ttyp;
+       struct taskdev *dev;
+
+       /* read stuff */
+       struct ipbuf_p *ipbuf_pvt_r;
+
+       /* write stuff */
+       struct ipbuf_p *ipbuf_pvt_w;
+
+       /* mmap stuff */
+       void *map_base;
+       size_t map_length;
+};
+
+#define sndtyp_acv(ttyp)       ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp)       (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp)                ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp)                (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp)       ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp)       ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp)       (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp)                ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp)                (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp)       ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVMD))
+
+static inline int has_taskdev_lock(struct taskdev *dev);
+static int dsp_rmdev_minor(unsigned char minor);
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
+static void taskdev_delete(unsigned char minor);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+       .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task;      /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid)   ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+               devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev)      up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+               devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev)     up_write(&(dev)->state_sem)
+
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf);
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf);
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf);
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count);
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf);
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf);
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf);
+
+#define __ATTR_RW(_name,_mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
+
+static struct device_attribute dev_attr_devname   = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate  = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname  = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp      = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz    = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt   = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink   = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz       = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap      = __ATTR_RO(mmap);
+
+static inline void set_taskdev_state(struct taskdev *dev, int state)
+{
+       pr_debug("omapdsp: devstate: CHANGE %s[%d]:\"%s\"->\"%s\"\n",
+                dev->name,
+                (dev->task ? dev->task->tid : -1),
+                devstate_name(dev->state),
+                devstate_name(state));
+       dev->state = state;
+}
+
+/*
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
+ */
+#define BUILD_DEVSTATE_LOCK_TIMEOUT(rw)                                                \
+static int devstate_##rw##_lock_timeout(struct taskdev *dev, long devstate,     \
+                                     int timeout)                              \
+{                                                                              \
+       DEFINE_WAIT(wait);                                                      \
+       down_##rw(&dev->state_sem);                                             \
+       while (!(dev->state & devstate)) {                                      \
+               up_##rw(&dev->state_sem);                                       \
+               prepare_to_wait(&dev->state_wait_q, &wait, TASK_INTERRUPTIBLE); \
+               if (!timeout)                                                   \
+                       timeout = MAX_SCHEDULE_TIMEOUT;                         \
+               timeout = schedule_timeout(timeout);                            \
+               finish_wait(&dev->state_wait_q, &wait);                         \
+               if (timeout == 0)                                               \
+                       return -ETIME;                                          \
+               if (signal_pending(current))                                    \
+                       return -EINTR;                                          \
+               down_##rw(&dev->state_sem);                                     \
+       }                                                                       \
+       return 0;                                                               \
+}
+BUILD_DEVSTATE_LOCK_TIMEOUT(read)
+BUILD_DEVSTATE_LOCK_TIMEOUT(write)
+
+#define BUILD_DEVSTATE_LOCK_AND_TEST(rw)                                       \
+static int devstate_##rw##_lock_and_test(struct taskdev *dev, long devstate)   \
+{                                                                              \
+       down_##rw(&dev->state_sem);                                             \
+       if (dev->state & devstate)                                              \
+               return 1;       /* success */                                   \
+       /* failure */                                                           \
+       up_##rw(&dev->state_sem);                                               \
+       return 0;                                                               \
+}
+BUILD_DEVSTATE_LOCK_AND_TEST(read)
+BUILD_DEVSTATE_LOCK_AND_TEST(write)
+
+static int taskdev_lock_interruptible(struct taskdev *dev,
+                                     struct mutex *lock)
+{
+       int ret;
+
+       if (has_taskdev_lock(dev))
+               ret = mutex_lock_interruptible(lock);
+       else {
+               if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
+                       return ret;
+               ret = mutex_lock_interruptible(lock);
+               mutex_unlock(&dev->lock);
+       }
+
+       return ret;
+}
+
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+                                              struct mutex *lock)
+{
+       int ret;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+               devstate_read_unlock(dev);
+
+       return ret;
+}
+
+static inline void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+                                                     struct mutex *lock)
+{
+       mutex_unlock(lock);
+       devstate_read_unlock(dev);
+}
+
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       if (sndtyp_wd(ttyp)) {
+               /* word receiving */
+               kfifo_reset(dev->rcvdt.fifo);
+       } else {
+               /* block receiving */
+               struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+               if (sndtyp_gbl(ttyp))
+                       ipblink_flush(&rcvdt->link);
+               else {
+                       ipblink_flush_pvt(&rcvdt->link);
+                       release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
+               printk(KERN_ERR
+                      "omapdsp: buffer size can be changed only for "
+                      "active word sending task.\n");
+               return -EINVAL;
+       }
+       if ((sz == 0) || (sz & 1)) {
+               printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
+                               "it must be even and non-zero value.\n", sz);
+               return -EINVAL;
+       }
+
+       if (kfifo_len(dev->rcvdt.fifo)) {
+               printk(KERN_ERR "omapdsp: buffer is not empty!\n");
+               return -EIO;
+       }
+
+       kfifo_free(dev->rcvdt.fifo);
+       dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
+       if (IS_ERR(dev->rcvdt.fifo)) {
+               printk(KERN_ERR
+                      "omapdsp: unable to change receive buffer size. "
+                      "(%ld bytes for %s)\n", sz, dev->name);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static inline int has_taskdev_lock(struct taskdev *dev)
+{
+       return (dev->lock_pid == current->pid);
+}
+
+static int taskdev_lock(struct taskdev *dev)
+{
+       if (mutex_lock_interruptible(&dev->lock))
+               return -EINTR;
+       dev->lock_pid = current->pid;
+       return 0;
+}
+
+static int taskdev_unlock(struct taskdev *dev)
+{
+       if (!has_taskdev_lock(dev)) {
+               printk(KERN_ERR
+                      "omapdsp: an illegal process attempted to "
+                      "unlock the dsptask lock!\n");
+               return -EINVAL;
+       }
+       dev->lock_pid = 0;
+       mutex_unlock(&dev->lock);
+       return 0;
+}
+
+static int dsp_task_config(struct dsptask *task, u8 tid)
+{
+       u16 ttyp;
+       int ret;
+
+       task->tid = tid;
+       dsptask[tid] = task;
+
+       /* TCFG request */
+       task->state = TASK_ST_CFGREQ;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_cmd = MBOX_CMD_DSP_TCFG;
+       mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (task->state != TASK_ST_READY) {
+               printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       if (strlen(task->name) <= 1)
+               sprintf(task->name, "%d", tid);
+       pr_info("omapdsp: task %d: name %s\n", tid, task->name);
+
+       ttyp = task->ttyp;
+
+       /*
+        * task info sanity check
+        */
+
+       /* task type check */
+       if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
+               printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
+                      tid, ttyp);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* private buffer address check */
+       if (sndtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if (rcvtyp_pvt(ttyp) &&
+           (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       /* mmap buffer configuration check */
+       if ((task->map_length > 0) &&
+           ((!ALIGN((unsigned long)task->map_base, PAGE_SIZE)) ||
+            (!ALIGN(task->map_length, PAGE_SIZE)) ||
+            (dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
+               printk(KERN_ERR
+                      "omapdsp: illegal mmap buffer address(0x%p) or "
+                      "length(0x%x).\n"
+                      "  It needs to be page-aligned and located at "
+                      "external memory.\n",
+                      task->map_base, task->map_length);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       return 0;
+
+fail_out:
+       dsptask[tid] = NULL;
+       return ret;
+}
+
+static void dsp_task_init(struct dsptask *task)
+{
+       mbcompose_send(TCTL, task->tid, TCTL_TINIT);
+}
+
+int dsp_task_config_all(u8 n)
+{
+       int i, ret;
+       struct taskdev *devheap;
+       struct dsptask *taskheap;
+       size_t devheapsz, taskheapsz;
+
+       pr_info("omapdsp: found %d task(s)\n", n);
+       if (n == 0)
+               return 0;
+
+       /*
+        * reducing kmalloc!
+        */
+       devheapsz  = sizeof(struct taskdev) * n;
+       taskheapsz = sizeof(struct dsptask) * n;
+       heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+       if (heap == NULL)
+               return -ENOMEM;
+       devheap  = heap;
+       taskheap = heap + devheapsz;
+
+       n_task = n;
+       for (i = 0; i < n; i++) {
+               struct taskdev *dev  = &devheap[i];
+               struct dsptask *task = &taskheap[i];
+
+               if ((ret = dsp_task_config(task, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_init(dev, task->name, i)) < 0)
+                       return ret;
+               if ((ret = taskdev_attach_task(dev, task)) < 0)
+                       return ret;
+               dsp_task_init(task);
+               pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+       }
+
+       return 0;
+}
+
+static void dsp_task_unconfig(struct dsptask *task)
+{
+       dsptask[task->tid] = NULL;
+}
+
+void dsp_task_unconfig_all(void)
+{
+       unsigned char minor;
+       u8 tid;
+       struct dsptask *task;
+
+       for (minor = 0; minor < n_task; minor++) {
+               /*
+                * taskdev[minor] can be NULL in case of
+                * configuration failure
+                */
+               if (taskdev[minor])
+                       taskdev_delete(minor);
+       }
+       for (; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor])
+                       dsp_rmdev_minor(minor);
+       }
+
+       for (tid = 0; tid < n_task; tid++) {
+               /*
+                * dsptask[tid] can be NULL in case of
+                * configuration failure
+                */
+               task = dsptask[tid];
+               if (task)
+                       dsp_task_unconfig(task);
+       }
+       for (; tid < TASKDEV_MAX; tid++) {
+               task = dsptask[tid];
+               if (task) {
+                       /*
+                        * on-demand tasks should be deleted in
+                        * rmdev_minor(), but just in case.
+                        */
+                       dsp_task_unconfig(task);
+                       kfree(task);
+               }
+       }
+
+       if (heap) {
+               kfree(heap);
+               heap = NULL;
+       }
+
+       n_task = 0;
+}
+
+static struct device_driver dsptask_driver = {
+       .name   = "dsptask",
+       .bus    = &dsptask_bus,
+};
+
+u8 dsp_task_count(void)
+{
+       return n_task;
+}
+
+int dsp_taskmod_busy(void)
+{
+       struct taskdev *dev;
+       unsigned char minor;
+       unsigned int usecount;
+
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               dev = taskdev[minor];
+               if (dev == NULL)
+                       continue;
+               if ((usecount = dev->usecount) > 0) {
+                       printk("dsp_taskmod_busy(): %s: usecount=%d\n",
+                              dev->name, usecount);
+                       return 1;
+               }
+/*
+               if ((dev->state & (TASKDEV_ST_ADDREQ |
+                                  TASKDEV_ST_DELREQ)) {
+*/
+               if (dev->state & TASKDEV_ST_ADDREQ) {
+                       printk("dsp_taskmod_busy(): %s is in %s\n",
+                              dev->name, devstate_name(dev->state));
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * DSP task device file operations
+ */
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+       DEFINE_WAIT(wait);
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+
+       prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (kfifo_len(dev->rcvdt.fifo) == 0)
+               schedule();
+       finish_wait(&dev->read_wait_q, &wait);
+       if (kfifo_len(dev->rcvdt.fifo) == 0) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+
+       ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+ up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       ssize_t ret = 0;
+       DEFINE_WAIT(wait);
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (ipblink_empty(&rcvdt->link))
+               schedule();
+       finish_wait(&dev->read_wait_q, &wait);
+       if (ipblink_empty(&rcvdt->link)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       /* copy from delayed IPBUF */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               if (!ipblink_empty(&rcvdt->link)) {
+                       struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+                       unsigned char *base, *src;
+                       size_t bkcnt;
+
+                       if (dsp_mem_enable(ipbp) < 0) {
+                               ret = -EBUSY;
+                               goto up_out;
+                       }
+                       base = MKVIRT(ipbp->ah, ipbp->al);
+                       bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+                       if (dsp_address_validate(base, bkcnt,
+                                                "task %s read buffer",
+                                                dev->task->name) < 0) {
+                               ret = -EINVAL;
+                               goto pv_out1;
+                       }
+                       if (dsp_mem_enable(base) < 0) {
+                               ret = -EBUSY;
+                               goto pv_out1;
+                       }
+                       src = base + rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = count;
+                               rcvdt->rp += count;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto pv_out2;
+                               }
+                               ret = bkcnt;
+                               ipblink_del_pvt(&rcvdt->link);
+                               release_ipbuf_pvt(ipbp);
+                               rcvdt->rp = 0;
+                       }
+               pv_out2:
+                       dsp_mem_disable(src);
+               pv_out1:
+                       dsp_mem_disable(ipbp);
+               }
+       } else {
+               /* global */
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               while (!ipblink_empty(&rcvdt->link)) {
+                       unsigned char *src;
+                       size_t bkcnt;
+                       struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+
+                       src = ipb_h->p->d + rcvdt->rp;
+                       bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
+                       if (bkcnt > count) {
+                               if (copy_to_user_dsp(buf, src, count)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += count;
+                               rcvdt->rp += count;
+                               break;
+                       } else {
+                               if (copy_to_user_dsp(buf, src, bkcnt)) {
+                                       ret = -EFAULT;
+                                       goto gb_out;
+                               }
+                               ret += bkcnt;
+                               buf += bkcnt;
+                               count -= bkcnt;
+                               ipblink_del_top(&rcvdt->link);
+                               unuse_ipbuf(ipb_h);
+                               rcvdt->rp = 0;
+                       }
+               }
+       gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+ up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
+
+       if (kfifo_len(dev->rcvdt.fifo) == 0) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+       int ret = 0;
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_read().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+
+       mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+                               &dev->read_wait_q);
+
+       if (ipblink_empty(&rcvdt->link)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       /*
+        * We will not receive more than requested count.
+        */
+       if (sndtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
+               size_t rcvcnt;
+               void *src;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               src = MKVIRT(ipbp->ah, ipbp->al);
+               rcvcnt = ((unsigned long)ipbp->c) * 2;
+               if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(src) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, src, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipblink_del_pvt(&rcvdt->link);
+               release_ipbuf_pvt(ipbp);
+               ret = count;
+pv_out2:
+               dsp_mem_disable(src);
+pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
+               size_t rcvcnt;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
+               if (count > rcvcnt)
+                       count = rcvcnt;
+               if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipblink_del_top(&rcvdt->link);
+               unuse_ipbuf(ipb_h);
+               ret = count;
+gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       u16 wd;
+       int ret = 0;
+       DEFINE_WAIT(wait);
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else {
+               /* force! */
+               count = 2;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (dev->wsz == 0)
+               schedule();
+       finish_wait(&dev->write_wait_q, &wait);
+       if (dev->wsz == 0) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       if (copy_from_user(&wd, buf, count)) {
+               ret = -EFAULT;
+               goto up_out;
+       }
+
+       spin_lock(&dev->wsz_lock);
+       if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+               spin_unlock(&dev->wsz_lock);
+               goto up_out;
+       }
+       ret = count;
+       if (rcvtyp_acv(dev->task->ttyp))
+               dev->wsz = 0;
+       spin_unlock(&dev->wsz_lock);
+
+ up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret = 0;
+       DEFINE_WAIT(wait);
+
+       if (count == 0) {
+               return 0;
+       } else if (count & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: odd count is illegal for DSP task device.\n");
+               return -EINVAL;
+       } else if ((int)buf & 0x1) {
+               printk(KERN_ERR
+                      "omapdsp: buf should be word aligned for "
+                      "dsp_task_write().\n");
+               return -EINVAL;
+       }
+
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
+
+       prepare_to_wait(&dev->write_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (dev->wsz == 0)
+               schedule();
+       finish_wait(&dev->write_wait_q, &wait);
+       if (dev->wsz == 0) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
+               goto up_out;
+       }
+
+       if (count > dev->wsz)
+               count = dev->wsz;
+
+       if (rcvtyp_pvt(dev->task->ttyp)) {
+               /* private */
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w;
+               unsigned char *dst;
+
+               if (dsp_mem_enable(ipbp) < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               dst = MKVIRT(ipbp->ah, ipbp->al);
+               if (dsp_address_validate(dst, count, "task %s write buffer",
+                                        dev->task->name) < 0) {
+                       ret = -EINVAL;
+                       goto pv_out1;
+               }
+               if (dsp_mem_enable(dst) < 0) {
+                       ret = -EBUSY;
+                       goto pv_out1;
+               }
+               if (copy_from_user_dsp(dst, buf, count)) {
+                       ret = -EFAULT;
+                       goto pv_out2;
+               }
+               ipbp->c = count/2;
+               ipbp->s = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+               }
+               spin_unlock(&dev->wsz_lock);
+       pv_out2:
+               dsp_mem_disable(dst);
+       pv_out1:
+               dsp_mem_disable(ipbp);
+       } else {
+               /* global */
+               struct ipbuf_head *ipb_h;
+
+               if (dsp_mem_enable_ipbuf() < 0) {
+                       ret = -EBUSY;
+                       goto up_out;
+               }
+               if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
+                       goto gb_out;
+               if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+                       release_ipbuf(ipb_h);
+                       ret = -EFAULT;
+                       goto gb_out;
+               }
+               ipb_h->p->c  = count/2;
+               ipb_h->p->sa = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
+                       if (rcvtyp_acv(dev->task->ttyp))
+                               dev->wsz = 0;
+                       ret = count;
+                       ipb_bsycnt_inc(&ipbcfg);
+               } else
+                       release_ipbuf(ipb_h);
+               spin_unlock(&dev->wsz_lock);
+       gb_out:
+               dsp_mem_disable_ipbuf();
+       }
+
+ up_out:
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
+       return ret;
+}
+
+static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
+{
+       unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task = dev->task;
+       unsigned int mask = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return 0;
+       poll_wait(file, &dev->read_wait_q, wait);
+       poll_wait(file, &dev->write_wait_q, wait);
+       if (sndtyp_psv(task->ttyp) ||
+           (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
+           (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
+               mask |= POLLIN | POLLRDNORM;
+       if (dev->wsz)
+               mask |= POLLOUT | POLLWRNORM;
+       devstate_read_unlock(dev);
+
+       return mask;
+}
+
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
+{
+       int tctl_argc;
+       struct mb_exarg mbarg, *mbargp;
+       int interactive;
+       u8 tid;
+       int ret = 0;
+
+       if (cmd < 0x8000) {
+               /*
+                * 0x0000 - 0x7fff
+                * system reserved TCTL commands
+                */
+               switch (cmd) {
+               case TCTL_TEN:
+               case TCTL_TDIS:
+                       tctl_argc = 0;
+                       interactive = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       /*
+        * 0x8000 - 0xffff
+        * user-defined TCTL commands
+        */
+       else if (cmd < 0x8100) {
+               /* 0x8000-0x80ff: no arg, non-interactive */
+               tctl_argc = 0;
+               interactive = 0;
+       } else if (cmd < 0x8200) {
+               /* 0x8100-0x81ff: 1 arg, non-interactive */
+               tctl_argc = 1;
+               interactive = 0;
+       } else if (cmd < 0x9000) {
+               /* 0x8200-0x8fff: reserved */
+               return -EINVAL;
+       } else if (cmd < 0x9100) {
+               /* 0x9000-0x90ff: no arg, interactive */
+               tctl_argc = 0;
+               interactive = 1;
+       } else if (cmd < 0x9200) {
+               /* 0x9100-0x91ff: 1 arg, interactive */
+               tctl_argc = 1;
+               interactive = 1;
+       } else {
+               /* 0x9200-0xffff: reserved */
+               return -EINVAL;
+       }
+
+       /*
+        * if argc < 0, use tctl_argc as is.
+        * if argc >= 0, check arg count.
+        */
+       if ((argc >= 0) && (argc != tctl_argc))
+               return -EINVAL;
+
+       /*
+        * issue TCTL
+        */
+       if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+               return -EINTR;
+
+       tid = dev->task->tid;
+       if (tctl_argc > 0) {
+               mbarg.argc = tctl_argc;
+               mbarg.tid  = tid;
+               mbarg.argv = argv;
+               mbargp = &mbarg;
+       } else
+               mbargp = NULL;
+
+       if (interactive) {
+               dev->tctl_stat = -EINVAL;
+
+               mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+                                             &dev->tctl_wait_q);
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       goto up_out;
+               }
+               if ((ret = dev->tctl_stat) < 0) {
+                       printk(KERN_ERR "omapdsp: TCTL not responding.\n");
+                       goto up_out;
+               }
+       } else
+               mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+       mutex_unlock(&dev->tctl_mutex);
+       return ret;
+}
+
+static int dsp_task_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       int ret;
+
+       if (cmd < 0x10000) {
+               /* issue TCTL */
+               u16 mbargv[1];
+
+               mbargv[0] = arg & 0xffff;
+               return dsp_tctl_issue(dev, cmd, -1, mbargv);
+       }
+
+       /* non TCTL ioctls */
+       switch (cmd) {
+
+       case TASK_IOCTL_LOCK:
+               ret = taskdev_lock(dev);
+               break;
+
+       case TASK_IOCTL_UNLOCK:
+               ret = taskdev_unlock(dev);
+               break;
+
+       case TASK_IOCTL_BFLSH:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_flush_buf(dev);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_SETBSZ:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_set_fifosz(dev, arg);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_GETNAME:
+               ret = 0;
+               if (copy_to_user((void __user *)arg, dev->name,
+                                strlen(dev->name) + 1))
+                       ret = -EFAULT;
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+
+       }
+
+       return ret;
+}
+
+static void dsp_task_mmap_open(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       omap_mmu_exmap_use(&dsp_mmu, task->map_base, len);
+}
+
+static void dsp_task_mmap_close(struct vm_area_struct *vma)
+{
+       struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
+       struct dsptask *task;
+       size_t len = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
+       task = dev->task;
+       omap_mmu_exmap_unuse(&dsp_mmu, task->map_base, len);
+}
+
+/**
+ * On demand page allocation is not allowed. The mapping area is defined by
+ * corresponding DSP tasks.
+ */
+static int dsp_task_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       return VM_FAULT_NOPAGE;
+}
+
+static struct vm_operations_struct dsp_task_vm_ops = {
+       .open = dsp_task_mmap_open,
+       .close = dsp_task_mmap_close,
+       .fault = dsp_task_mmap_fault,
+};
+
+static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       void *tmp_vadr;
+       unsigned long tmp_padr, tmp_vmadr, off;
+       size_t req_len, tmp_len;
+       unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+       struct dsptask *task;
+       int ret = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+       task = dev->task;
+
+       /*
+        * Don't swap this area out
+        * Don't dump this area to a core file
+        */
+       vma->vm_flags |= VM_RESERVED | VM_IO;
+
+       /* Do not cache this area */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       req_len = vma->vm_end - vma->vm_start;
+       off = vma->vm_pgoff << PAGE_SHIFT;
+       tmp_vmadr = vma->vm_start;
+       tmp_vadr = task->map_base + off;
+       do {
+               tmp_padr = omap_mmu_virt_to_phys(&dsp_mmu, tmp_vadr, &tmp_len);
+               if (tmp_padr == 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: illegal address "
+                              "for mmap: %p", task->name, tmp_vadr);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+               if (tmp_len > req_len)
+                       tmp_len = req_len;
+
+               pr_debug("omapdsp: mmap info: "
+                        "vmadr = %08lx, padr = %08lx, len = %x\n",
+                        tmp_vmadr, tmp_padr, tmp_len);
+               if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT,
+                                   tmp_len, vma->vm_page_prot) != 0) {
+                       printk(KERN_ERR
+                              "omapdsp: task %s: remap_page_range() failed.\n",
+                              task->name);
+                       /* partial mapping will be cleared in upper layer */
+                       ret = -EINVAL;
+                       goto unlock_out;
+               }
+
+               req_len   -= tmp_len;
+               tmp_vmadr += tmp_len;
+               tmp_vadr  += tmp_len;
+       } while (req_len);
+
+       vma->vm_ops = &dsp_task_vm_ops;
+       vma->vm_private_data = dev;
+       omap_mmu_exmap_use(&dsp_mmu, task->map_base, vma->vm_end - vma->vm_start);
+
+unlock_out:
+       devstate_read_unlock(dev);
+       return ret;
+}
+
+static int dsp_task_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev;
+       int ret = 0;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
+               return -ENODEV;
+
+ restart:
+       mutex_lock(&dev->usecount_lock);
+       down_write(&dev->state_sem);
+
+       /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+       case TASKDEV_ST_NOTASK:
+               break;
+       case TASKDEV_ST_ATTACHED:
+               goto attached;
+
+       case TASKDEV_ST_INVALID:
+               up_write(&dev->state_sem);
+               mutex_unlock(&dev->usecount_lock);
+               return -ENODEV;
+
+       case TASKDEV_ST_FREEZED:
+       case TASKDEV_ST_KILLING:
+       case TASKDEV_ST_GARBAGE:
+       case TASKDEV_ST_DELREQ:
+               /* on the kill process. wait until it becomes NOTASK. */
+               up_write(&dev->state_sem);
+               mutex_unlock(&dev->usecount_lock);
+               if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+                       return -EINTR;
+               devstate_write_unlock(dev);
+               goto restart;
+       }
+
+       /* NOTASK */
+       set_taskdev_state(dev, TASKDEV_ST_ADDREQ);
+       /* wake up twch daemon for tadd */
+       dsp_twch_touch();
+       up_write(&dev->state_sem);
+       if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+                               TASKDEV_ST_ADDFAIL) < 0) {
+               /* cancelled */
+               if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+                       mutex_unlock(&dev->usecount_lock);
+                       /* out of control ??? */
+                       return -EINTR;
+               }
+               set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+               ret = -EINTR;
+               goto change_out;
+       }
+       if (dev->state & TASKDEV_ST_ADDFAIL) {
+               printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+                      dev->name);
+               ret = -EBUSY;
+               set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+               goto change_out;
+       }
+
+ attached:
+       ret = proc_list_add(&dev->proc_list_lock,
+                           &dev->proc_list, current, file);
+       if (ret)
+               goto out;
+
+       dev->usecount++;
+       file->f_op = &dev->fops;
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_map_update(current);
+       dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
+       return 0;
+
+ change_out:
+       wake_up_interruptible_all(&dev->state_wait_q);
+ out:
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return ret;
+}
+
+static int dsp_task_release(struct inode *inode, struct file *file)
+{
+       unsigned int minor = MINOR(inode->i_rdev);
+       struct taskdev *dev = taskdev[minor];
+
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+       if (has_taskdev_lock(dev))
+               taskdev_unlock(dev);
+
+       proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+       mutex_lock(&dev->usecount_lock);
+       if (--dev->usecount > 0) {
+               /* other processes are using this device. no state change. */
+               mutex_unlock(&dev->usecount_lock);
+               return 0;
+       }
+
+       /* usecount == 0 */
+       down_write(&dev->state_sem);
+
+       /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_KILLING:
+               break;
+
+       case TASKDEV_ST_GARBAGE:
+               set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               if (is_dynamic_task(minor)) {
+                       set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+                       /* wake up twch daemon for tdel */
+                       dsp_twch_touch();
+               }
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
+       return 0;
+}
+
+/*
+ * mkdev / rmdev
+ */
+int dsp_mkdev(char *name)
+{
+       struct taskdev *dev;
+       int status;
+       unsigned char minor;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* naming check */
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device name %s is already "
+                              "in use.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* find free minor number */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] == NULL)
+                       goto do_make;
+       }
+       printk(KERN_ERR "omapdsp: Too many task devices.\n");
+       ret = -EBUSY;
+       goto out;
+
+do_make:
+       if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       if ((status = taskdev_init(dev, name, minor)) < 0) {
+               kfree(dev);
+               ret = status;
+               goto out;
+       }
+       ret = minor;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+int dsp_rmdev(char *name)
+{
+       unsigned char minor;
+       int status;
+       int ret;
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* find in dynamic devices */
+       for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+                       goto do_remove;
+       }
+
+       /* find in static devices */
+       for (minor = 0; minor < n_task; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device %s is static.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
+       return -EINVAL;
+
+do_remove:
+       ret = minor;
+       if ((status = dsp_rmdev_minor(minor)) < 0)
+               ret = status;
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_rmdev_minor(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       while (!down_write_trylock(&dev->state_sem)) {
+               down_read(&dev->state_sem);
+               if (dev->state & (TASKDEV_ST_ATTACHED |
+                                 TASKDEV_ST_FREEZED)) {
+                       /*
+                        * task is working. kill it.
+                        * ATTACHED -> FREEZED can be changed under
+                        * down_read of state_sem..
+                        */
+                       set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+                       wake_up_interruptible_all(&dev->read_wait_q);
+                       wake_up_interruptible_all(&dev->write_wait_q);
+                       wake_up_interruptible_all(&dev->tctl_wait_q);
+               }
+               up_read(&dev->state_sem);
+               schedule();
+       }
+
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+
+       case TASKDEV_ST_NOTASK:
+       case TASKDEV_ST_INVALID:
+               /* fine */
+               goto notask;
+
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               /* task is working. kill it. */
+               set_taskdev_state(dev, TASKDEV_ST_KILLING);
+               up_write(&dev->state_sem);
+               dsp_tdel_bh(dev, TDEL_KILL);
+               goto invalidate;
+
+       case TASKDEV_ST_ADDREQ:
+               /* open() is waiting. drain it. */
+               set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_DELREQ:
+               /* nobody is waiting. */
+               set_taskdev_state(dev, TASKDEV_ST_NOTASK);
+               wake_up_interruptible_all(&dev->state_wait_q);
+               break;
+
+       case TASKDEV_ST_ADDING:
+       case TASKDEV_ST_DELING:
+       case TASKDEV_ST_KILLING:
+       case TASKDEV_ST_GARBAGE:
+       case TASKDEV_ST_ADDFAIL:
+               /* transient state. wait for a moment. */
+               break;
+
+       }
+
+       up_write(&dev->state_sem);
+
+invalidate:
+       /* wait for some time and hope the state is settled */
+       devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+       if (!(dev->state & TASKDEV_ST_NOTASK)) {
+               printk(KERN_WARNING
+                      "omapdsp: illegal device state (%s) on rmdev %s.\n",
+                      devstate_name(dev->state), dev->name);
+       }
+notask:
+       set_taskdev_state(dev, TASKDEV_ST_INVALID);
+       devstate_read_unlock(dev);
+
+       taskdev_delete(minor);
+       kfree(dev);
+
+       return 0;
+}
+
+static struct file_operations dsp_task_fops = {
+       .owner   = THIS_MODULE,
+       .poll    = dsp_task_poll,
+       .ioctl   = dsp_task_ioctl,
+       .open    = dsp_task_open,
+       .release = dsp_task_release,
+};
+
+static void dsptask_dev_release(struct device *dev)
+{
+}
+
+static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
+{
+       int ret;
+       struct device *task_dev;
+
+       taskdev[minor] = dev;
+
+       spin_lock_init(&dev->proc_list_lock);
+       INIT_LIST_HEAD(&dev->proc_list);
+       init_waitqueue_head(&dev->read_wait_q);
+       init_waitqueue_head(&dev->write_wait_q);
+       init_waitqueue_head(&dev->tctl_wait_q);
+       mutex_init(&dev->read_mutex);
+       mutex_init(&dev->write_mutex);
+       mutex_init(&dev->tctl_mutex);
+       mutex_init(&dev->lock);
+       spin_lock_init(&dev->wsz_lock);
+       dev->tctl_ret = -EINVAL;
+       dev->lock_pid = 0;
+
+       strncpy(dev->name, name, TNM_LEN);
+       dev->name[TNM_LEN-1] = '\0';
+       set_taskdev_state(dev, (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK);
+       dev->usecount = 0;
+       mutex_init(&dev->usecount_lock);
+       memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
+
+       dev->dev.parent = omap_dsp->dev;
+       dev->dev.bus = &dsptask_bus;
+       sprintf(dev->dev.bus_id, "dsptask%d", minor);
+       dev->dev.release = dsptask_dev_release;
+       ret = device_register(&dev->dev);
+       if (ret) {
+               printk(KERN_ERR "device_register failed: %d\n", ret);
+               return ret;
+       }
+       ret = device_create_file(&dev->dev, &dev_attr_devname);
+       if (ret)
+               goto fail_create_devname;
+       ret = device_create_file(&dev->dev, &dev_attr_devstate);
+       if (ret)
+               goto fail_create_devstate;
+       ret = device_create_file(&dev->dev, &dev_attr_proc_list);
+       if (ret)
+               goto fail_create_proclist;
+
+       task_dev = device_create(dsp_task_class, NULL,
+                                MKDEV(OMAP_DSP_TASK_MAJOR, minor), NULL,
+                                "dsptask%d", (int)minor);
+
+       if (unlikely(IS_ERR(task_dev))) {
+               ret = -EINVAL;
+               goto fail_create_taskclass;
+       }
+
+       init_waitqueue_head(&dev->state_wait_q);
+       init_rwsem(&dev->state_sem);
+
+       return 0;
+
+ fail_create_taskclass:
+       device_remove_file(&dev->dev, &dev_attr_proc_list);
+ fail_create_proclist:
+       device_remove_file(&dev->dev, &dev_attr_devstate);
+ fail_create_devstate:
+       device_remove_file(&dev->dev, &dev_attr_devname);
+ fail_create_devname:
+       device_unregister(&dev->dev);
+       return ret;
+}
+
+static void taskdev_delete(unsigned char minor)
+{
+       struct taskdev *dev = taskdev[minor];
+
+       if (!dev)
+               return;
+       device_remove_file(&dev->dev, &dev_attr_devname);
+       device_remove_file(&dev->dev, &dev_attr_devstate);
+       device_remove_file(&dev->dev, &dev_attr_proc_list);
+       device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
+       device_unregister(&dev->dev);
+       proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
+       taskdev[minor] = NULL;
+}
+
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+{
+       u16 ttyp = task->ttyp;
+       int ret;
+
+       dev->fops.read =
+               sndtyp_acv(ttyp) ?
+               sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
+               /* sndtyp_bk */   dsp_task_read_bk_acv:
+               /* sndtyp_psv */
+               sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
+               /* sndtyp_bk */   dsp_task_read_bk_psv;
+       if (sndtyp_wd(ttyp)) {
+               /* word */
+               size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
+
+               dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
+                                             &dev->read_lock);
+               if (IS_ERR(dev->rcvdt.fifo)) {
+                       printk(KERN_ERR
+                              "omapdsp: unable to allocate receive buffer. "
+                              "(%d bytes for %s)\n", fifosz, dev->name);
+                       return -ENOMEM;
+               }
+       } else {
+               /* block */
+               INIT_IPBLINK(&dev->rcvdt.bk.link);
+               dev->rcvdt.bk.rp = 0;
+       }
+
+       dev->fops.write =
+               rcvtyp_wd(ttyp) ? dsp_task_write_wd:
+               /* rcvbyp_bk */   dsp_task_write_bk;
+       dev->wsz = rcvtyp_acv(ttyp) ? 0 :               /* active */
+               rcvtyp_wd(ttyp)  ? 2 :          /* passive word */
+               ipbcfg.lsz*2;   /* passive block */
+
+       if (task->map_length)
+               dev->fops.mmap = dsp_task_mmap;
+
+       ret = device_create_file(&dev->dev, &dev_attr_taskname);
+       if (unlikely(ret))
+               goto fail_create_taskname;
+       ret = device_create_file(&dev->dev, &dev_attr_ttyp);
+       if (unlikely(ret))
+               goto fail_create_ttyp;
+       ret = device_create_file(&dev->dev, &dev_attr_wsz);
+       if (unlikely(ret))
+               goto fail_create_wsz;
+       if (task->map_length) {
+               ret = device_create_file(&dev->dev, &dev_attr_mmap);
+               if (unlikely(ret))
+                       goto fail_create_mmap;
+       }
+       if (sndtyp_wd(ttyp)) {
+               ret = device_create_file(&dev->dev, &dev_attr_fifosz);
+               if (unlikely(ret))
+                       goto fail_create_fifosz;
+               ret = device_create_file(&dev->dev, &dev_attr_fifocnt);
+               if (unlikely(ret))
+                       goto fail_create_fifocnt;
+       } else {
+               ret = device_create_file(&dev->dev, &dev_attr_ipblink);
+               if (unlikely(ret))
+                       goto fail_create_ipblink;
+       }
+
+       dev->task = task;
+       task->dev = dev;
+
+       return 0;
+
+ fail_create_fifocnt:
+       device_remove_file(&dev->dev, &dev_attr_fifosz);
+ fail_create_ipblink:
+ fail_create_fifosz:
+       if (task->map_length)
+               device_remove_file(&dev->dev, &dev_attr_mmap);
+ fail_create_mmap:
+       device_remove_file(&dev->dev, &dev_attr_wsz);
+ fail_create_wsz:
+       device_remove_file(&dev->dev, &dev_attr_ttyp);
+ fail_create_ttyp:
+       device_remove_file(&dev->dev, &dev_attr_taskname);
+ fail_create_taskname:
+       if (task->map_length)
+               dev->fops.mmap = NULL;
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+
+       if (sndtyp_wd(ttyp))
+               kfifo_free(dev->rcvdt.fifo);
+
+       dev->task = NULL;
+
+       return ret;
+}
+
+static void taskdev_detach_task(struct taskdev *dev)
+{
+       u16 ttyp = dev->task->ttyp;
+
+       device_remove_file(&dev->dev, &dev_attr_taskname);
+       device_remove_file(&dev->dev, &dev_attr_ttyp);
+       if (sndtyp_wd(ttyp)) {
+               device_remove_file(&dev->dev, &dev_attr_fifosz);
+               device_remove_file(&dev->dev, &dev_attr_fifocnt);
+       } else
+               device_remove_file(&dev->dev, &dev_attr_ipblink);
+       device_remove_file(&dev->dev, &dev_attr_wsz);
+       if (dev->task->map_length) {
+               device_remove_file(&dev->dev, &dev_attr_mmap);
+               dev->fops.mmap = NULL;
+       }
+
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+       if (sndtyp_wd(ttyp))
+               kfifo_free(dev->rcvdt.fifo);
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       pr_info("omapdsp: taskdev %s disabled.\n", dev->name);
+       dev->task = NULL;
+}
+
+/*
+ * tadd / tdel / tkill
+ */
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
+{
+       struct dsptask *task;
+       struct mb_exarg arg;
+       u8 tid, tid_response;
+       u16 argv[2];
+       int ret = 0;
+
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tadd. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       set_taskdev_state(dev, TASKDEV_ST_ADDING);
+       devstate_write_unlock(dev);
+
+       if (adr == TADD_ABORTADR) {
+               /* aborting tadd intentionally */
+               pr_info("omapdsp: tadd address is ABORTADR.\n");
+               goto fail_out;
+       }
+       if (adr >= DSPSPACE_SIZE) {
+               printk(KERN_ERR
+                      "omapdsp: illegal address 0x%08x for tadd\n", adr);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+
+       adr >>= 1;      /* word address */
+       argv[0] = adr >> 16;    /* addrh */
+       argv[1] = adr & 0xffff; /* addrl */
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               ret = -EINTR;
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TADD;
+       arg.tid  = TID_ANON;
+       arg.argc = 2;
+       arg.argv = argv;
+
+       if (dsp_mem_sync_inc() < 0) {
+               printk(KERN_ERR "omapdsp: memory sync failed!\n");
+               ret = -EBUSY;
+               goto fail_out;
+       }
+       mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
+
+       tid = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid == TID_ANON) {
+               printk(KERN_ERR "omapdsp: tadd failed!\n");
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((tid < n_task) || dsptask[tid]) {
+               printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid);
+               ret = -EINVAL;
+               goto fail_out;
+       }
+       if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto del_out;
+       }
+
+       if ((ret = dsp_task_config(task, tid)) < 0)
+               goto free_out;
+
+       if (strcmp(dev->name, task->name)) {
+               printk(KERN_ERR
+                      "omapdsp: task name (%s) doesn't match with "
+                      "device name (%s).\n", task->name, dev->name);
+               ret = -EINVAL;
+               goto free_out;
+       }
+
+       if ((ret = taskdev_attach_task(dev, task)) < 0)
+               goto free_out;
+
+       dsp_task_init(task);
+       pr_info("omapdsp: taskdev %s enabled.\n", dev->name);
+       set_taskdev_state(dev, TASKDEV_ST_ATTACHED);
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return 0;
+
+free_out:
+       kfree(task);
+
+del_out:
+       printk(KERN_ERR "omapdsp: deleting the task...\n");
+
+       set_taskdev_state(dev, TASKDEV_ST_DELING);
+
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               printk(KERN_ERR "omapdsp: aborting tdel process. "
+                               "DSP side could be corrupted.\n");
+               goto fail_out;
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+       if (tid_response != tid)
+               printk(KERN_ERR "omapdsp: tdel failed. "
+                               "DSP side could be corrupted.\n");
+
+fail_out:
+       set_taskdev_state(dev, TASKDEV_ST_ADDFAIL);
+       wake_up_interruptible_all(&dev->state_wait_q);
+       return ret;
+}
+
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = minor;
+       if ((status = dsp_tadd(dev, adr)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
+               printk(KERN_ERR
+                      "omapdsp: taskdev %s is not requesting for tdel. "
+                      "(state is %s)\n", dev->name, devstate_name(dev->state));
+               return -EINVAL;
+       }
+       set_taskdev_state(dev, TASKDEV_ST_DELING);
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_SAFE);
+}
+
+int dsp_tdel_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tdel(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+       while (!down_write_trylock(&dev->state_sem)) {
+               if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+                                                      TASKDEV_ST_FREEZED))) {
+                       printk(KERN_ERR
+                              "omapdsp: task has not been attached for "
+                              "taskdev %s\n", dev->name);
+                       return -EINVAL;
+               }
+               /* ATTACHED -> FREEZED can be changed under read semaphore. */
+               set_taskdev_state(dev, TASKDEV_ST_FREEZED);
+               wake_up_interruptible_all(&dev->read_wait_q);
+               wake_up_interruptible_all(&dev->write_wait_q);
+               wake_up_interruptible_all(&dev->tctl_wait_q);
+               devstate_read_unlock(dev);
+               schedule();
+       }
+
+       if (!(dev->state & (TASKDEV_ST_ATTACHED |
+                           TASKDEV_ST_FREEZED))) {
+               printk(KERN_ERR
+                      "omapdsp: task has not been attached for taskdev %s\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       if (!is_dynamic_task(dev->task->tid)) {
+               printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       set_taskdev_state(dev, TASKDEV_ST_KILLING);
+       devstate_write_unlock(dev);
+
+       return dsp_tdel_bh(dev, TDEL_KILL);
+}
+
+int dsp_tkill_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tkill(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
+{
+       struct dsptask *task;
+       u8 tid, tid_response;
+       int ret = 0;
+
+       task = dev->task;
+       tid = task->tid;
+       if (mutex_lock_interruptible(&cfg_lock)) {
+               if (type == TDEL_SAFE) {
+                       set_taskdev_state(dev, TASKDEV_ST_DELREQ);
+                       return -EINTR;
+               } else {
+                       tid_response = TID_ANON;
+                       ret = -EINTR;
+                       goto detach_out;
+               }
+       }
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
+       tid_response = cfg_tid;
+       cfg_tid = TID_ANON;
+       cfg_cmd = 0;
+       mutex_unlock(&cfg_lock);
+
+detach_out:
+       taskdev_detach_task(dev);
+       dsp_task_unconfig(task);
+       kfree(task);
+
+       if (tid_response != tid) {
+               printk(KERN_ERR "omapdsp: %s failed!\n",
+                      (type == TDEL_SAFE) ? "tdel" : "tkill");
+               ret = -EINVAL;
+       }
+       down_write(&dev->state_sem);
+       set_taskdev_state(dev, (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+                                          TASKDEV_ST_NOTASK);
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+
+       return ret;
+}
+
+/*
+ * state inquiry
+ */
+long taskdev_state_stale(unsigned char minor)
+{
+       if (taskdev[minor]) {
+               long state = taskdev[minor]->state;
+               taskdev[minor]->state |= TASKDEV_ST_STALE;
+               return state;
+       } else
+               return TASKDEV_ST_NOTASK;
+}
+
+/*
+ * functions called from mailbox interrupt routine
+ */
+void mbox_wdsnd(struct mbcmd *mb)
+{
+       unsigned int n;
+       u8 tid = mb->cmd_l;
+       u16 data = mb->data;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_bk(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDSND from block sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_psv(task->ttyp) &&
+           !waitqueue_active(&task->dev->read_wait_q)) {
+               printk(KERN_WARNING
+                      "mbox: WDSND from passive sending task (task%d) "
+                      "without request!\n", tid);
+               return;
+       }
+
+       n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
+                     sizeof(data));
+       if (n != sizeof(data))
+               printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
+
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_wdreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: WDREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = 2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bksnd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 bid = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_head *ipb_h;
+       u16 cnt;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+       ipb_bsycnt_dec(&ipbcfg);
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from word sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sndtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSND from private sending task! (task%d)\n", tid);
+               goto unuse_ipbuf_out;
+       }
+       if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
+               return;
+       }
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       cnt = ipb_h->p->c;
+       if (cnt > ipbcfg.lsz) {
+               printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+                      cnt, ipbcfg.lsz);
+               goto unuse_ipbuf_out;
+       }
+
+       if (cnt == 0) {
+               /* 0-byte send from DSP */
+               unuse_ipbuf_nowait(ipb_h);
+               goto done;
+       }
+       ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
+       /* we keep coming bid and return alternative line to DSP. */
+       balance_ipbuf();
+
+done:
+       wake_up_interruptible(&task->dev->read_wait_q);
+       return;
+
+unuse_ipbuf_out:
+       unuse_ipbuf_nowait(ipb_h);
+       return;
+}
+
+void mbox_bkreq(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       u16 cnt = mb->data;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_pvt(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from private receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQ from passive receiving task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = cnt*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_bkyld(struct mbcmd *mb)
+{
+       u16 bid = mb->data;
+       struct ipbuf_head *ipb_h;
+
+       if (bid >= ipbcfg.ln) {
+               printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
+               return;
+       }
+       ipb_h = bid_to_ipbuf(bid);
+
+       /* should be done in DSP, but just in case. */
+       ipb_h->p->next = BID_NULL;
+
+       /* we don't need to sync with DSP */
+       ipb_bsycnt_dec(&ipbcfg);
+       release_ipbuf(ipb_h);
+}
+
+void mbox_bksndp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (sndtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from word sending task! (task%d)\n", tid);
+               return;
+       }
+       if (sndtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKSNDP from non-private sending task! (task%d)\n",
+                      tid);
+               return;
+       }
+
+       /*
+        * we should not have delayed block at this point
+        * because read() routine releases the lock of the buffer and
+        * until then DSP can't send next data.
+        */
+
+       ipbp = task->ipbuf_pvt_r;
+       if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
+               return;
+       }
+       pr_debug("mbox: ipbuf_pvt_r->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       ipblink_add_pvt(&task->dev->rcvdt.bk.link);
+       wake_up_interruptible(&task->dev->read_wait_q);
+}
+
+void mbox_bkreqp(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+       struct ipbuf_p *ipbp;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
+               return;
+       }
+       if (rcvtyp_wd(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from word receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_gbl(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
+               return;
+       }
+       if (rcvtyp_psv(task->ttyp)) {
+               printk(KERN_ERR
+                      "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
+               return;
+       }
+
+       ipbp = task->ipbuf_pvt_w;
+       if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
+               return;
+       }
+       pr_debug("mbox: ipbuf_pvt_w->a = 0x%08lx\n",
+              MKLONG(ipbp->ah, ipbp->al));
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = ipbp->c*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
+}
+
+void mbox_tctl(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
+               return;
+       }
+
+       if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+               printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
+               return;
+       }
+
+       task->dev->tctl_stat = mb->data;
+       wake_up_interruptible(&task->dev->tctl_wait_q);
+}
+
+void mbox_tcfg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       struct dsptask *task = dsptask[tid];
+       u16 *tnm;
+       volatile u16 *buf;
+       int i;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
+               return;
+       }
+       if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+               printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
+               return;
+       }
+
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
+
+       /*
+        * read configuration data on system IPBUF
+        */
+       buf = ipbuf_sys_da->d;
+       task->ttyp        = buf[0];
+       task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+       task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+       task->map_base    = MKVIRT(buf[5], buf[6]);
+       task->map_length  = MKLONG(buf[7], buf[8]) << 1;        /* word -> byte */
+       tnm               = MKVIRT(buf[9], buf[10]);
+       release_ipbuf_pvt(ipbuf_sys_da);
+       dsp_mem_disable(ipbuf_sys_da);
+
+       /*
+        * copy task name string
+        */
+       if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
+               task->name[0] = '\0';
+               goto out;
+       }
+
+       for (i = 0; i < TNM_LEN-1; i++) {
+               /* avoiding byte access */
+               u16 tmp = tnm[i];
+               task->name[i] = tmp & 0x00ff;
+               if (!tmp)
+                       break;
+       }
+       task->name[TNM_LEN-1] = '\0';
+
+       task->state = TASK_ST_READY;
+out:
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tadd(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+               printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_tdel(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+               printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
+               return;
+       }
+       cfg_tid = tid;
+       wake_up_interruptible(&cfg_wait_q);
+}
+
+void mbox_err_fatal(u8 tid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
+
+       if ((tid >= TASKDEV_MAX) || (task == NULL)) {
+               printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
+               return;
+       }
+
+       /* wake up waiting processes */
+       dev = task->dev;
+       wake_up_interruptible_all(&dev->read_wait_q);
+       wake_up_interruptible_all(&dev->write_wait_q);
+       wake_up_interruptible_all(&dev->tctl_wait_q);
+}
+
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
+static int dbg_rp;
+
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
+{
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               dbg_buf = NULL;
+               dbg_buf_sz = 0;
+               dbg_line_sz = 0;
+               dbg_rp = 0;
+               return 0;
+       }
+#endif
+
+       if (dsp_address_validate(buf, sz, "debug buffer") < 0)
+               return -1;
+
+       if (lsz > sz) {
+               printk(KERN_ERR
+                      "omapdsp: dbg_buf lsz (%d) is greater than its "
+                      "buffer size (%d)\n", lsz, sz);
+               return -1;
+       }
+
+       dbg_buf = buf;
+       dbg_buf_sz = sz;
+       dbg_line_sz = lsz;
+       dbg_rp = 0;
+
+       return 0;
+}
+
+void dsp_dbg_stop(void)
+{
+       dbg_buf = NULL;
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb);
+#endif
+
+void mbox_dbg(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       int cnt = mb->data;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       int i;
+
+#ifdef OLD_BINARY_SUPPORT
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               mbox_dbg_old(mb);
+               return;
+       }
+#endif
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dbg_buf == NULL) {
+               printk(KERN_ERR "mbox: DBG command received, but "
+                      "dbg_buf has not been configured yet.\n");
+               return;
+       }
+
+       if (dsp_mem_enable(dbg_buf) < 0)
+               return;
+
+       src = &dbg_buf[dbg_rp];
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that dbg_buf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       pr_info("%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       pr_info("%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               pr_info("%s\n", s);
+       }
+       if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
+               dbg_rp = 0;
+
+       dsp_mem_disable(dbg_buf);
+}
+
+#ifdef OLD_BINARY_SUPPORT
+static void mbox_dbg_old(struct mbcmd *mb)
+{
+       u8 tid = mb->cmd_l;
+       char s[80], *s_end = &s[79], *p;
+       u16 *src;
+       volatile u16 *buf;
+       int cnt;
+       int i;
+
+       if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
+               return;
+       }
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
+               return;
+       }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+               goto out1;
+       }
+       buf = ipbuf_sys_da->d;
+       cnt = buf[0];
+       src = MKVIRT(buf[1], buf[2]);
+       if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
+               goto out2;
+
+       if (dsp_mem_enable(src) < 0)
+               goto out2;
+
+       p = s;
+       for (i = 0; i < cnt; i++) {
+               u16 tmp;
+               /*
+                * Be carefull that ipbuf should not be read with
+                * 1-byte access since it might be placed in DARAM/SARAM
+                * and it can cause unexpected byteswap.
+                * For example,
+                *   *(p++) = *(src++) & 0xff;
+                * causes 1-byte access!
+                */
+               tmp = *src++;
+               *(p++) = tmp & 0xff;
+               if (*(p-1) == '\n') {
+                       *p = '\0';
+                       pr_info("%s", s);
+                       p = s;
+                       continue;
+               }
+               if (p == s_end) {
+                       *p = '\0';
+                       pr_info("%s\n", s);
+                       p = s;
+                       continue;
+               }
+       }
+       if (p > s) {
+               *p = '\0';
+               pr_info("%s\n", s);
+       }
+
+       dsp_mem_disable(src);
+out2:
+       release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+       dsp_mem_disable(ipbuf_sys_da);
+}
+#endif /* OLD_BINARY_SUPPORT */
+
+/*
+ * sysfs files: for each device
+ */
+
+/* devname */
+static ssize_t devname_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "%s\n", to_taskdev(d)->name);
+}
+
+/* devstate */
+static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
+}
+
+/* proc_list */
+static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
+                             char *buf)
+{
+       struct taskdev *dev;
+       struct proc_list *pl;
+       int len = 0;
+
+       dev = to_taskdev(d);
+       spin_lock(&dev->proc_list_lock);
+       list_for_each_entry(pl, &dev->proc_list, list_head) {
+               /* need to lock tasklist_lock before calling
+                * find_task_by_pid_type. */
+               if (find_task_by_pid_type_ns(PIDTYPE_PID, pl->pid, &init_pid_ns) != NULL)
+                       len += sprintf(buf + len, "%d\n", pl->pid);
+               read_unlock(&tasklist_lock);
+       }
+       spin_unlock(&dev->proc_list_lock);
+
+       return len;
+}
+
+/* taskname */
+static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
+                            char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       int len;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       len = sprintf(buf, "%s\n", dev->task->name);
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* ttyp */
+static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct taskdev *dev = to_taskdev(d);
+       u16 ttyp;
+       int len = 0;
+
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       ttyp = dev->task->ttyp;
+       len += sprintf(buf + len, "0x%04x\n", ttyp);
+       len += sprintf(buf + len, "%s %s send\n",
+                       (sndtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (sndtyp_wd(ttyp))  ? "word" :
+                       (sndtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+       len += sprintf(buf + len, "%s %s receive\n",
+                       (rcvtyp_acv(ttyp)) ? "active" :
+                                            "passive",
+                       (rcvtyp_wd(ttyp))  ? "word" :
+                       (rcvtyp_pvt(ttyp)) ? "private block" :
+                                            "global block");
+
+       devstate_read_unlock(dev);
+       return len;
+}
+
+/* fifosz */
+static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
+                          char *buf)
+{
+       struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->size);
+}
+
+static int fifosz_store(struct device *d, struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct taskdev *dev = to_taskdev(d);
+       unsigned long fifosz;
+       int ret;
+
+       fifosz = simple_strtol(buf, NULL, 10);
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
+       ret = taskdev_set_fifosz(dev, fifosz);
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+
+       return (ret < 0) ? ret : strlen(buf);
+}
+
+/* fifocnt */
+static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
+       return sprintf(buf, "%d\n", fifo->size);
+}
+
+/* ipblink */
+static inline char *bid_name(u16 bid)
+{
+       static char s[6];
+
+       switch (bid) {
+       case BID_NULL:
+               return "NULL";
+       case BID_PVT:
+               return "PRIVATE";
+       default:
+               sprintf(s, "%d", bid);
+               return s;
+       }
+}
+
+static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
+                           char *buf)
+{
+       struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
+       int len;
+
+       spin_lock(&rcvdt->link.lock);
+       len = sprintf(buf, "top  %s\ntail %s\n",
+                     bid_name(rcvdt->link.top), bid_name(rcvdt->link.tail));
+       spin_unlock(&rcvdt->link.lock);
+
+       return len;
+}
+
+/* wsz */
+static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
+                       char *buf)
+{
+       return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
+}
+
+/* mmap */
+static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
+                        char *buf)
+{
+       struct dsptask *task = to_taskdev(d)->task;
+       return sprintf(buf, "0x%p 0x%x\n", task->map_base, task->map_length);
+}
+
+/*
+ * called from ipbuf_show()
+ */
+int ipbuf_is_held(u8 tid, u16 bid)
+{
+       struct dsptask *task = dsptask[tid];
+       struct ipblink *link;
+       u16 b;
+       int ret = 0;
+
+       if (task == NULL)
+               return 0;
+
+       link = &task->dev->rcvdt.bk.link;
+       spin_lock(&link->lock);
+       ipblink_for_each(b, link) {
+               if (b == bid) { /* found */
+                       ret = 1;
+                       break;
+               }
+       }
+       spin_unlock(&link->lock);
+
+       return ret;
+}
+
+int __init dsp_taskmod_init(void)
+{
+       int retval;
+
+       memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
+       memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
+
+       retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask",
+                                &dsp_task_fops);
+       if (retval < 0) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register task device: %d\n", retval);
+               return retval;
+       }
+
+       retval = bus_register(&dsptask_bus);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task bus: %d\n",
+                      retval);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       retval = driver_register(&dsptask_driver);
+       if (retval) {
+               printk(KERN_ERR
+                      "omapdsp: failed to register DSP task driver: %d\n",
+                      retval);
+               bus_unregister(&dsptask_bus);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+       dsp_task_class = class_create(THIS_MODULE, "dsptask");
+       if (IS_ERR(dsp_task_class)) {
+               printk(KERN_ERR "omapdsp: failed to create DSP task class\n");
+               driver_unregister(&dsptask_driver);
+               bus_unregister(&dsptask_bus);
+               unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void dsp_taskmod_exit(void)
+{
+       class_destroy(dsp_task_class);
+       driver_unregister(&dsptask_driver);
+       bus_unregister(&dsptask_bus);
+       unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask");
+}
diff --git a/drivers/dsp/dspgateway/taskwatch.c b/drivers/dsp/dspgateway/taskwatch.c
new file mode 100644 (file)
index 0000000..a5fea3d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <mach/dsp.h>
+#include <asm/io.h>
+#include "dsp_mbcmd.h"
+#include "dsp.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
+static unsigned int change_cnt;
+
+void dsp_twch_touch(void)
+{
+       change_cnt++;
+       wake_up_interruptible(&read_wait_q);
+}
+
+/*
+ * @count: represents the device counts of the user's interst
+ */
+static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       long taskstat[TASKDEV_MAX];
+       int devcount = count / sizeof(long);
+       int i;
+       DEFINE_WAIT(wait);
+
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
+               printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
+               return -EINVAL;
+       }
+
+       prepare_to_wait(&read_wait_q, &wait, TASK_INTERRUPTIBLE);
+       if (change_cnt == 0)    /* last check */
+               schedule();
+       finish_wait(&read_wait_q, &wait);
+
+       /* unconfigured while waiting ;-( */
+       if ((change_cnt == 0) && (dsp_cfgstat_get_stat() != CFGSTAT_READY))
+               return -EINVAL;
+
+       if (devcount > TASKDEV_MAX)
+               devcount = TASKDEV_MAX;
+
+       count = devcount * sizeof(long);
+       change_cnt = 0;
+       for (i = 0; i < devcount; i++) {
+               /*
+                * once the device state is read, the 'STALE' bit will be set
+                * so that the Dynamic Loader can distinguish the new request
+                * from the old one.
+                */
+               taskstat[i] = taskdev_state_stale(i);
+       }
+
+       if (copy_to_user(buf, taskstat, count))
+               return -EFAULT;
+
+       return count;
+}
+
+static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &read_wait_q, wait);
+       if (change_cnt)
+               mask |= POLLIN | POLLRDNORM;
+
+       return mask;
+}
+
+static int dsp_twch_ioctl(struct inode *inode, struct file *file,
+                         unsigned int cmd, unsigned long arg)
+{
+       int ret;
+
+       switch (cmd) {
+       case TWCH_IOCTL_MKDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_mkdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_RMDEV:
+               {
+                       char name[TNM_LEN];
+                       if (copy_from_user(name, (void __user *)arg, TNM_LEN))
+                               return -EFAULT;
+                       name[TNM_LEN-1] = '\0';
+                       ret = dsp_rmdev(name);
+                       break;
+               }
+
+       case TWCH_IOCTL_TADD:
+               {
+                       struct omap_dsp_taddinfo ti;
+                       if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
+                               return -EFAULT;
+                       ret = dsp_tadd_minor(ti.minor, ti.taskadr);
+                       break;
+               }
+
+       case TWCH_IOCTL_TDEL:
+               ret = dsp_tdel_minor(arg);
+               break;
+
+       case TWCH_IOCTL_TKILL:
+               ret = dsp_tkill_minor(arg);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return ret;
+}
+
+struct file_operations dsp_twch_fops = {
+       .owner = THIS_MODULE,
+       .read  = dsp_twch_read,
+       .poll  = dsp_twch_poll,
+       .ioctl = dsp_twch_ioctl,
+};
+
+void dsp_twch_start(void)
+{
+       change_cnt = 1;         /* first read will not wait */
+}
+
+void dsp_twch_stop(void)
+{
+       wake_up_interruptible(&read_wait_q);
+}
diff --git a/drivers/dsp/dspgateway/uaccess_dsp.S b/drivers/dsp/dspgateway/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/drivers/dsp/dspgateway/uaccess_dsp.h b/drivers/dsp/dspgateway/uaccess_dsp.h
new file mode 100644 (file)
index 0000000..839a51a
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
+ *
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _OMAP_DSP_UACCESS_DSP_H
+#define _OMAP_DSP_UACCESS_DSP_H
+
+#include <asm/uaccess.h>
+#include <mach/dsp_common.h>
+#include "dsp.h"
+
+#define HAVE_ASM_COPY_FROM_USER_DSP_2B
+
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+extern unsigned long __copy_from_user_dsp_2b(void *to,
+                                                 const void __user *from);
+extern unsigned long __copy_to_user_dsp_2b(void __user *to,
+                                               const void *from);
+#endif
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_from_user_dsp_2b(void *to,
+                                                     const void *from)
+{
+       unsigned short tmp;
+
+       if (__copy_from_user(&tmp, from, 2))
+               return 2;
+       /* expecting compiler to generate "strh" instruction */
+       *((unsigned short *)to) = tmp;
+       return 0;
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_from_user_dsp(void *to, const void *from,
+                                                  unsigned long n)
+{
+       if (access_ok(VERIFY_READ, from, n)) {
+               if ((is_dsp_internal_mem(to)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_from_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_from_user_dsp_2b(to, from))
+#else
+                               if (copy_from_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_from_user(to, from, n);
+               }
+       }
+       else    /* security hole - plug it */
+               memzero(to, n);
+       return n;
+}
+
+#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B
+static inline unsigned long copy_to_user_dsp_2b(void *to, const void *from)
+{
+       /* expecting compiler to generate "strh" instruction */
+       unsigned short tmp = *(unsigned short *)from;
+
+       return __copy_to_user(to, &tmp, 2);
+}
+#endif
+
+/*
+ * @n must be multiple of 2
+ */
+static inline unsigned long copy_to_user_dsp(void *to, const void *from,
+                                                unsigned long n)
+{
+       if (access_ok(VERIFY_WRITE, to, n)) {
+               if ((is_dsp_internal_mem(from)) &&
+                   (((unsigned long)to & 2) || (n & 2))) {
+                       /*
+                        * DARAM/SARAM with odd word alignment
+                        */
+                       unsigned long n4;
+                       unsigned long last_n;
+
+                       /* dest not aligned -- copy 2 bytes */
+                       if (((unsigned long)to & 2) && (n >= 2)) {
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return n;
+                               to += 2;
+                               from += 2;
+                               n -= 2;
+                       }
+                       /* middle 4*n bytes */
+                       last_n = n & 2;
+                       n4 = n - last_n;
+                       if ((n = __copy_to_user(to, from, n4)) != 0)
+                               return n + last_n;
+                       /* last 2 bytes */
+                       if (last_n) {
+                               to += n4;
+                               from += n4;
+#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B
+                               if (__copy_to_user_dsp_2b(to, from))
+#else
+                               if (copy_to_user_dsp_2b(to, from))
+#endif
+                                       return 2;
+                               n = 0;
+                       }
+               } else {
+                       /*
+                        * DARAM/SARAM with 4-byte alignment or
+                        * external memory
+                        */
+                       n = __copy_to_user(to, from, n);
+               }
+       }
+       return n;
+}
+
+#endif /* _OMAP_DSP_UACCESS_DSP_H */
index dbd42d6c93a701b2a0e52ec4a118f36ed538701e..293b4a7060dec39d56bfc82d4b29e69096452ebf 100644 (file)
@@ -127,6 +127,13 @@ config GPIO_PCF857X
          This driver provides an in-kernel interface to those GPIOs using
          platform-neutral GPIO calls.
 
+config GPIO_TWL4030
+       tristate "TWL4030/TPS659x0 GPIO Driver"
+       depends on TWL4030_CORE && GPIOLIB
+       help
+         Say yes here to access the GPIO signals of various multi-function
+         power management chips from Texas Instruments.
+
 comment "PCI GPIO expanders:"
 
 config GPIO_BT8XX
index 01b4bbde1956e48933d23d60c782ef94f8dff63e..6aafdeb9ad03c04a4e932c33c7ff3d7f53954cd4 100644 (file)
@@ -9,4 +9,5 @@ obj-$(CONFIG_GPIO_MAX732X)      += max732x.o
 obj-$(CONFIG_GPIO_MCP23S08)    += mcp23s08.o
 obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
+obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
 obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
index 8d2940517c99221c33e3bf200ac53a82214cebee..2c16981653b98246fe92be2347be97031574e303 100644 (file)
@@ -1008,6 +1008,24 @@ int __gpio_cansleep(unsigned gpio)
 }
 EXPORT_SYMBOL_GPL(__gpio_cansleep);
 
+/**
+ * __gpio_to_irq() - return the IRQ corresponding to a GPIO
+ * @gpio: gpio whose IRQ will be returned (already requested)
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_to_irq().
+ * It returns the number of the IRQ signaled by this (input) GPIO,
+ * or a negative errno.
+ */
+int __gpio_to_irq(unsigned gpio)
+{
+       struct gpio_chip        *chip;
+
+       chip = gpio_to_chip(gpio);
+       return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(__gpio_to_irq);
+
 
 
 /* There's no value in making it easy to inline GPIO calls that may sleep.
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
new file mode 100644 (file)
index 0000000..582eec1
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * twl4030_gpio.c -- access to GPIOs on TWL4030/TPS659x0 chips
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Code re-arranged and cleaned up by:
+ *     Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ *     Andy Lowe / Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The GPIO "subchip" supports 18 GPIOs which can be configured as
+ * inputs or outputs, with pullups or pulldowns on each pin.  Each
+ * GPIO can trigger interrupts on either or both edges.
+ *
+ * GPIO interrupts can be fed to either of two IRQ lines; this is
+ * intended to support multiple hosts.
+ *
+ * There are also two LED pins used sometimes as output-only GPIOs.
+ *
+ * FIXME code currently only handles the first IRQ line.
+ */
+
+
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+        */
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       /* same effect on other architectures */
+       set_irq_noprobe(irq);
+#endif
+}
+
+static struct gpio_chip twl_gpiochip;
+static int twl4030_gpio_irq_base;
+static int twl4030_gpio_irq_end;
+
+/* genirq interfaces are not available to modules */
+#ifdef MODULE
+#define is_module()    true
+#else
+#define is_module()    false
+#endif
+
+/* GPIO_CTRL Fields */
+#define MASK_GPIO_CTRL_GPIO0CD1                BIT(0)
+#define MASK_GPIO_CTRL_GPIO1CD2                BIT(1)
+#define MASK_GPIO_CTRL_GPIO_ON         BIT(2)
+
+/* Mask for GPIO registers when aggregated into a 32-bit integer */
+#define GPIO_32_MASK                   0x0003ffff
+
+/* Data structures */
+static DEFINE_MUTEX(gpio_lock);
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+/* protect what irq_chip modifies through its helper task */
+static DEFINE_SPINLOCK(gpio_spinlock);
+
+/* shadow the imr register; updates are delayed */
+static u32 gpio_imr_shadow;
+static bool gpio_pending_mask;
+
+/* bitmask of requests to set gpio irq trigger type */
+static unsigned int gpio_pending_trigger;
+
+/* pointer to helper thread */
+static struct task_struct *gpio_helper_thread;
+
+/*
+ * Helper functions to read and write the GPIO ISR and IMR registers as
+ * 32-bit integers. Functions return 0 on success, non-zero otherwise.
+ * The caller must hold gpio_lock.
+ */
+
+/* NOTE:  only the IRQ dispatcher may read ISR; reading it has
+ * side effects, because of the clear-on-read mechanism (COR=1).
+ */
+static int gpio_read_isr(unsigned int *isr)
+{
+       int ret;
+
+       *isr = 0;
+       ret = twl4030_i2c_read(TWL4030_MODULE_GPIO, (u8 *) isr,
+                       REG_GPIO_ISR1A, 3);
+       le32_to_cpup(isr);
+       *isr &= GPIO_32_MASK;
+
+       return ret;
+}
+
+/* IMR is written only during initialization and
+ * by request of the irq_chip code.
+ */
+static int gpio_write_imr(unsigned int imr)
+{
+       imr &= GPIO_32_MASK;
+       /*
+        * The buffer passed to the twl4030_i2c_write() routine must have an
+        * extra byte at the beginning reserved for its internal use.
+        */
+       imr <<= 8;
+       imr = cpu_to_le32(imr);
+       return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &imr,
+                               REG_GPIO_IMR1A, 3);
+}
+
+/*
+ * These are the irqchip methods for the TWL4030 GPIO interrupts.
+ * Our IRQ handle method doesn't call these, but they will be called by
+ * other routines such as setup_irq() and enable_irq().  They are called
+ * with cpu interrupts disabled and with a lock on the irq_desc.lock
+ * spinlock.  This complicates matters, because accessing the TWL4030 GPIO
+ * interrupt controller requires I2C bus transactions that can't be initiated
+ * in this context.  Our solution is to defer accessing the interrupt
+ * controller to a kernel thread.
+ */
+
+static void twl4030_gpio_irq_ack(unsigned int irq)
+{
+       /* NOP -- dispatcher acks when it reads ISR */
+}
+
+static void twl4030_gpio_irq_mask(unsigned int irq)
+{
+       int gpio = irq - twl4030_gpio_irq_base;
+       u32 mask = 1 << gpio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_spinlock, flags);
+       gpio_pending_mask = true;
+       gpio_imr_shadow |= mask;
+       if (gpio_helper_thread && gpio_helper_thread->state != TASK_RUNNING)
+               wake_up_process(gpio_helper_thread);
+       spin_unlock_irqrestore(&gpio_spinlock, flags);
+}
+
+static void twl4030_gpio_irq_unmask(unsigned int irq)
+{
+       int gpio = irq - twl4030_gpio_irq_base;
+       u32 mask = 1 << gpio;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_spinlock, flags);
+       gpio_pending_mask = true;
+       gpio_imr_shadow &= ~mask;
+       if (gpio_helper_thread && gpio_helper_thread->state != TASK_RUNNING)
+               wake_up_process(gpio_helper_thread);
+       spin_unlock_irqrestore(&gpio_spinlock, flags);
+}
+
+static int twl4030_gpio_irq_set_type(unsigned int irq, unsigned trigger)
+{
+       struct irq_desc *desc = irq_desc + irq;
+       int gpio = irq - twl4030_gpio_irq_base;
+       unsigned long flags;
+
+       trigger &= IRQ_TYPE_SENSE_MASK;
+       if (trigger & ~IRQ_TYPE_EDGE_BOTH)
+               return -EINVAL;
+       if ((desc->status & IRQ_TYPE_SENSE_MASK) == trigger)
+               return 0;
+
+       desc->status &= ~IRQ_TYPE_SENSE_MASK;
+       desc->status |= trigger;
+
+       spin_lock_irqsave(&gpio_spinlock, flags);
+       gpio_pending_trigger |= (1 << gpio);
+       if (gpio_helper_thread && gpio_helper_thread->state != TASK_RUNNING)
+               wake_up_process(gpio_helper_thread);
+       spin_unlock_irqrestore(&gpio_spinlock, flags);
+
+       return 0;
+}
+
+static struct irq_chip twl4030_gpio_irq_chip = {
+       .name           = "twl4030",
+       .ack            = twl4030_gpio_irq_ack,
+       .mask           = twl4030_gpio_irq_mask,
+       .unmask         = twl4030_gpio_irq_unmask,
+       .set_type       = twl4030_gpio_irq_set_type,
+};
+
+
+/*
+ * To configure TWL4030 GPIO module registers
+ */
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+       return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+}
+
+/*
+ * To read a TWL4030 GPIO module register
+ */
+static inline int gpio_twl4030_read(u8 address)
+{
+       u8 data;
+       int ret = 0;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+       return (ret < 0) ? ret : data;
+}
+
+/*
+ * twl4030 GPIO request function
+ */
+int twl4030_request_gpio(int gpio)
+{
+       int ret = 0;
+
+       if (unlikely(gpio >= TWL4030_GPIO_MAX))
+               return -EPERM;
+
+       ret = gpio_request(twl_gpiochip.base + gpio, NULL);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&gpio_lock);
+       if (gpio_usage_count & BIT(gpio)) {
+               ret = -EBUSY;
+       } else {
+               /* First time usage? - switch on GPIO module */
+               if (!gpio_usage_count) {
+                       ret = gpio_twl4030_write(REG_GPIO_CTRL,
+                                       MASK_GPIO_CTRL_GPIO_ON);
+
+               }
+               if (!ret)
+                       gpio_usage_count |= BIT(gpio);
+               else
+                       gpio_free(twl_gpiochip.base + gpio);
+       }
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_request_gpio);
+
+/*
+ * TWL4030 GPIO free module
+ */
+int twl4030_free_gpio(int gpio)
+{
+       int ret = 0;
+
+       if (unlikely(gpio >= TWL4030_GPIO_MAX))
+               return -EPERM;
+
+       mutex_lock(&gpio_lock);
+
+       if ((gpio_usage_count & BIT(gpio)) == 0) {
+               ret = -EPERM;
+       } else {
+               gpio_usage_count &= ~BIT(gpio);
+               gpio_free(twl_gpiochip.base + gpio);
+       }
+
+       /* Last time usage? - switch off GPIO module */
+       if (ret == 0 && !gpio_usage_count)
+               ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_free_gpio);
+
+static int twl4030_set_gpio_direction(int gpio, int is_input)
+{
+       u8 d_bnk = gpio >> 3;
+       u8 d_msk = BIT(gpio & 0x7);
+       u8 reg = 0;
+       u8 base = REG_GPIODATADIR1 + d_bnk;
+       int ret = 0;
+
+       mutex_lock(&gpio_lock);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               if (is_input)
+                       reg = ret & ~d_msk;
+               else
+                       reg = ret | d_msk;
+
+               ret = gpio_twl4030_write(base, reg);
+       }
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+
+static int twl4030_set_gpio_dataout(int gpio, int enable)
+{
+       u8 d_bnk = gpio >> 3;
+       u8 d_msk = BIT(gpio & 0x7);
+       u8 base = 0;
+
+       if (enable)
+               base = REG_SETGPIODATAOUT1 + d_bnk;
+       else
+               base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+       return gpio_twl4030_write(base, d_msk);
+}
+
+int twl4030_get_gpio_datain(int gpio)
+{
+       u8 d_bnk = gpio >> 3;
+       u8 d_off = gpio & 0x7;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & BIT(gpio))))
+               return -EPERM;
+
+       base = REG_GPIODATAIN1 + d_bnk;
+       ret = gpio_twl4030_read(base);
+       if (ret > 0)
+               ret = (ret >> d_off) & 0x1;
+
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_get_gpio_datain);
+
+static int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
+{
+       u8 c_bnk = gpio >> 2;
+       u8 c_off = (gpio & 0x3) * 2;
+       u8 c_msk = 0;
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       base = REG_GPIO_EDR1 + c_bnk;
+
+       if (edge & IRQ_TYPE_EDGE_RISING)
+               c_msk |= BIT(c_off + 1);
+       if (edge & IRQ_TYPE_EDGE_FALLING)
+               c_msk |= BIT(c_off);
+
+       mutex_lock(&gpio_lock);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               /* clear the previous rising/falling values */
+               reg = (u8) ret;
+               reg &= ~(0x3 << c_off);
+               reg |= c_msk;
+               ret = gpio_twl4030_write(base, reg);
+       }
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+
+/*
+ * Configure debounce timing value for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_debounce(int gpio, int enable)
+{
+       u8 d_bnk = gpio >> 3;
+       u8 d_msk = BIT(gpio & 0x7);
+       u8 reg = 0;
+       u8 base = 0;
+       int ret = 0;
+
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & BIT(gpio))))
+               return -EPERM;
+
+       base = REG_GPIO_DEBEN1 + d_bnk;
+       mutex_lock(&gpio_lock);
+       ret = gpio_twl4030_read(base);
+       if (ret >= 0) {
+               if (enable)
+                       reg = ret | d_msk;
+               else
+                       reg = ret & ~d_msk;
+
+               ret = gpio_twl4030_write(base, reg);
+       }
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_debounce);
+
+#if 0
+/*
+ * Configure Card detect for GPIO pin on TWL4030
+ *
+ * This means:  VMMC1 or VMMC2 is enabled or disabled based
+ * on the status of GPIO-0 or GPIO-1 pins (respectively).
+ */
+int twl4030_set_gpio_card_detect(int gpio, int enable)
+{
+       u8 reg = 0;
+       u8 msk = (1 << gpio);
+       int ret = 0;
+
+       /* Only GPIO 0 or 1 can be used for CD feature.. */
+       if (unlikely((gpio >= TWL4030_GPIO_MAX)
+               || !(gpio_usage_count & BIT(gpio))
+               || (gpio >= TWL4030_GPIO_MAX_CD))) {
+               return -EPERM;
+       }
+
+       mutex_lock(&gpio_lock);
+       ret = gpio_twl4030_read(REG_GPIO_CTRL);
+       if (ret >= 0) {
+               if (enable)
+                       reg = (u8) (ret | msk);
+               else
+                       reg = (u8) (ret & ~msk);
+
+               ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
+       }
+       mutex_unlock(&gpio_lock);
+       return ret;
+}
+#endif
+
+/* MODULE FUNCTIONS */
+
+/*
+ * gpio_helper_thread() is a kernel thread that is awakened by irq_chip
+ * methods to update IRQ masks and trigger modes.
+ *
+ * We must do this in a thread rather than in irq_chip methods because of the
+ * need to access the TWL4030 via the I2C bus.  Note that we don't need to be
+ * concerned about race conditions where the request to unmask a GPIO interrupt
+ * has already been cancelled before this thread does the unmasking.  If a GPIO
+ * interrupt is improperly unmasked, then the IRQ handler for it will mask it
+ * when an interrupt occurs.
+ */
+static int twl4030_gpio_helper_thread(void *dev)
+{
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               int irq;
+               bool do_mask;
+               u32 local_imr;
+               unsigned int gpio_trigger;
+
+               spin_lock_irq(&gpio_spinlock);
+
+               do_mask = gpio_pending_mask;
+               gpio_pending_mask = false;
+               local_imr = gpio_imr_shadow;
+
+               gpio_trigger = gpio_pending_trigger;
+               gpio_pending_trigger = 0;
+
+               spin_unlock_irq(&gpio_spinlock);
+
+               if (do_mask) {
+                       int status = gpio_write_imr(local_imr);
+
+                       if (status)
+                               dev_err(dev, "write IMR err %d\n", status);
+               }
+
+               for (irq = twl4030_gpio_irq_base;
+                               gpio_trigger;
+                               gpio_trigger >>= 1, irq++) {
+                       struct irq_desc *desc;
+                       unsigned type;
+
+                       if (!(gpio_trigger & 0x1))
+                               continue;
+
+                       desc = irq_desc + irq;
+                       spin_lock_irq(&desc->lock);
+                       type = desc->status & IRQ_TYPE_SENSE_MASK;
+                       spin_unlock_irq(&desc->lock);
+
+                       twl4030_set_gpio_edge_ctrl(irq - twl4030_gpio_irq_base,
+                                       type);
+               }
+
+               spin_lock_irq(&gpio_spinlock);
+               if (!gpio_pending_mask && !gpio_pending_trigger)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_irq(&gpio_spinlock);
+
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+/*
+ * do_twl4030_gpio_module_irq() is the desc->handle method for the twl4030 gpio
+ * module interrupt.  It executes in kernel thread context.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * We query the gpio module interrupt controller in the twl4030 to determine
+ * which gpio lines are generating interrupt requests, and then call the
+ * desc->handle method for each gpio that needs service.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+       int gpio_irq;
+       unsigned int gpio_isr;
+
+       /* PIH irqs like this can't be individually masked or acked ...
+        * so we don't even call the PIH irq_chip stub methods.
+        */
+       local_irq_enable();
+       if (gpio_read_isr(&gpio_isr))
+               gpio_isr = 0;
+       local_irq_disable();
+
+       for (gpio_irq = twl4030_gpio_irq_base; 0 != gpio_isr;
+               gpio_isr >>= 1, gpio_irq++) {
+               if (gpio_isr & 0x1)
+                       generic_handle_irq(gpio_irq);
+       }
+}
+
+/*----------------------------------------------------------------------*/
+
+static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       return twl4030_set_gpio_direction(offset, 1);
+}
+
+static int twl_get(struct gpio_chip *chip, unsigned offset)
+{
+       int status = twl4030_get_gpio_datain(offset);
+
+       return (status < 0) ? 0 : status;
+}
+
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+       twl4030_set_gpio_dataout(offset, value);
+       return twl4030_set_gpio_direction(offset, 0);
+}
+
+static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       twl4030_set_gpio_dataout(offset, value);
+}
+
+static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       /* NOTE: assumes IRQs are set up ... */
+       return twl4030_gpio_irq_base + offset;
+}
+
+static struct gpio_chip twl_gpiochip = {
+       .label                  = "twl4030",
+       .owner                  = THIS_MODULE,
+       .direction_input        = twl_direction_in,
+       .get                    = twl_get,
+       .direction_output       = twl_direction_out,
+       .set                    = twl_set,
+       .to_irq                 = twl_to_irq,
+       .can_sleep              = 1,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
+{
+       u8              message[6];
+       unsigned        i, gpio_bit;
+
+       /* For most pins, a pulldown was enabled by default.
+        * We should have data that's specific to this board.
+        */
+       for (gpio_bit = 1, i = 1; i < 6; i++) {
+               u8              bit_mask;
+               unsigned        j;
+
+               for (bit_mask = 0, j = 0; j < 8; j += 2, gpio_bit <<= 1) {
+                       if (ups & gpio_bit)
+                               bit_mask |= 1 << (j + 1);
+                       else if (downs & gpio_bit)
+                               bit_mask |= 1 << (j + 0);
+               }
+               message[i] = bit_mask;
+       }
+
+       return twl4030_i2c_write(TWL4030_MODULE_GPIO, message,
+                               REG_GPIOPUPDCTR1, 5);
+}
+
+static int gpio_twl4030_remove(struct platform_device *pdev);
+
+static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
+{
+       struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+       int irq = 0;
+
+       /* All GPIO interrupts are initially masked */
+       gpio_pending_mask = false;
+       gpio_imr_shadow = GPIO_32_MASK;
+       ret = gpio_write_imr(gpio_imr_shadow);
+
+       twl4030_gpio_irq_base = pdata->irq_base;
+       twl4030_gpio_irq_end = pdata->irq_end;
+
+       if ((twl4030_gpio_irq_end - twl4030_gpio_irq_base) > 0) {
+               if (is_module()) {
+                       dev_err(&pdev->dev,
+                               "can't dispatch IRQs from modules\n");
+                       goto no_irqs;
+               }
+               if (twl4030_gpio_irq_end > NR_IRQS) {
+                       dev_err(&pdev->dev,
+                               "last IRQ is too large: %d\n",
+                               twl4030_gpio_irq_end);
+                       return -EINVAL;
+               }
+       } else {
+               dev_notice(&pdev->dev,
+                       "no IRQs being dispatched\n");
+               goto no_irqs;
+       }
+
+       if (!ret) {
+               /*
+                * Create a kernel thread to handle deferred operations on gpio
+                * interrupts.
+                */
+               gpio_helper_thread = kthread_create(twl4030_gpio_helper_thread,
+                               &pdev->dev, "twl4030 gpio");
+               if (!gpio_helper_thread) {
+                       dev_err(&pdev->dev,
+                               "could not create helper thread!\n");
+                       ret = -ENOMEM;
+               }
+       }
+
+       if (!ret) {
+               /* install an irq handler for each of the gpio interrupts */
+               for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end;
+                               irq++) {
+                       set_irq_chip_and_handler(irq, &twl4030_gpio_irq_chip,
+                                       handle_edge_irq);
+                       activate_irq(irq);
+               }
+
+               /* gpio module IRQ */
+               irq = platform_get_irq(pdev, 0);
+
+               /* COR=1 means irqs are acked by reading ISR
+                * PENDDIS=0 means pending events enabled
+                * EXCLEN=0 means route to both irq lines
+                */
+               gpio_twl4030_write(REG_GPIO_SIH_CTRL,
+                               TWL4030_SIH_CTRL_COR_MASK);
+
+               /*
+                * Install an irq handler to demultiplex the gpio module
+                * interrupt.
+                */
+               set_irq_chained_handler(irq, do_twl4030_gpio_module_irq);
+               wake_up_process(gpio_helper_thread);
+
+               dev_info(&pdev->dev, "IRQ %d chains IRQs %d..%d\n", irq,
+                       twl4030_gpio_irq_base, twl4030_gpio_irq_end - 1);
+       }
+
+no_irqs:
+       if (!ret) {
+               /*
+                * NOTE:  boards may waste power if they don't set pullups
+                * and pulldowns correctly ... default for non-ULPI pins is
+                * pulldown, and some other pins may have external pullups
+                * or pulldowns.  Careful!
+                */
+               ret = gpio_twl4030_pulls(pdata->pullups, pdata->pulldowns);
+               if (ret)
+                       dev_dbg(&pdev->dev, "pullups %.05x %.05x --> %d\n",
+                                       pdata->pullups, pdata->pulldowns,
+                                       ret);
+
+               twl_gpiochip.base = pdata->gpio_base;
+               twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
+               twl_gpiochip.dev = &pdev->dev;
+
+               ret = gpiochip_add(&twl_gpiochip);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                                       "could not register gpiochip, %d\n",
+                                       ret);
+                       twl_gpiochip.ngpio = 0;
+                       gpio_twl4030_remove(pdev);
+               } else if (pdata->setup) {
+                       int status;
+
+                       status = pdata->setup(&pdev->dev,
+                                       pdata->gpio_base, TWL4030_GPIO_MAX);
+                       if (status)
+                               dev_dbg(&pdev->dev, "setup --> %d\n", status);
+               }
+       }
+
+       return ret;
+}
+
+static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
+{
+       struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int status;
+       int irq;
+
+       if (pdata->teardown) {
+               status = pdata->teardown(&pdev->dev,
+                               pdata->gpio_base, TWL4030_GPIO_MAX);
+               if (status) {
+                       dev_dbg(&pdev->dev, "teardown --> %d\n", status);
+                       return status;
+               }
+       }
+
+       status = gpiochip_remove(&twl_gpiochip);
+       if (status < 0)
+               return status;
+
+       if (is_module() || (twl4030_gpio_irq_end - twl4030_gpio_irq_base) <= 0)
+               return 0;
+
+       /* uninstall the gpio demultiplexing interrupt handler */
+       irq = platform_get_irq(pdev, 0);
+       set_irq_handler(irq, NULL);
+
+       /* uninstall the irq handler for each of the gpio interrupts */
+       for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end; irq++)
+               set_irq_handler(irq, NULL);
+
+       /* stop the gpio helper kernel thread */
+       if (gpio_helper_thread) {
+               kthread_stop(gpio_helper_thread);
+               gpio_helper_thread = NULL;
+       }
+
+       return 0;
+}
+
+/* Note:  this hardware lives inside an I2C-based multi-function device. */
+MODULE_ALIAS("platform:twl4030_gpio");
+
+static struct platform_driver gpio_twl4030_driver = {
+       .driver.name    = "twl4030_gpio",
+       .driver.owner   = THIS_MODULE,
+       .probe          = gpio_twl4030_probe,
+       .remove         = __devexit_p(gpio_twl4030_remove),
+};
+
+static int __init gpio_twl4030_init(void)
+{
+       return platform_driver_register(&gpio_twl4030_driver);
+}
+subsys_initcall(gpio_twl4030_init);
+
+static void __exit gpio_twl4030_exit(void)
+{
+       platform_driver_unregister(&gpio_twl4030_driver);
+}
+module_exit(gpio_twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("GPIO interface for TWL4030");
+MODULE_LICENSE("GPL");
index d402e8d813ce2628d0fa7f079267ad1cdfbada14..390c6fa4efad6dddce3fecea5e898603876634f7 100644 (file)
@@ -836,6 +836,22 @@ config SENSORS_APPLESMC
          Say Y here if you have an applicable laptop and want to experience
          the awesome power of applesmc.
 
+config SENSORS_TSC210X
+       tristate "TI TSC210x battery & temperature sensors"
+       depends on HWMON && SPI_MASTER
+       select SPI_TSC210X
+       help
+         Say Y if your board has a TSC210x chip and you want to
+         have its battery state, auxiliary input and/or temperature
+         sensors exported through hwmon.
+
+         This driver can also be built as a module.  In this case
+         the module will be called tsc210x_sensors.
+
+config SENSORS_OMAP34XX
+       tristate "TI OMAP34xx internal temperature sensor"
+       depends on ARCH_OMAP3 && HIGH_RES_TIMERS
+
 config HWMON_DEBUG_CHIP
        bool "Hardware Monitoring Chip debugging messages"
        default n
index 950134ab842666a1c4ccb7d2b224c2b62d8af0dd..2580d5d91d520038e623306aa6867abaf1c22870 100644 (file)
@@ -73,7 +73,9 @@ obj-$(CONFIG_SENSORS_VT1211)  += vt1211.o
 obj-$(CONFIG_SENSORS_VT8231)   += vt8231.o
 obj-$(CONFIG_SENSORS_W83627EHF)        += w83627ehf.o
 obj-$(CONFIG_SENSORS_W83L785TS)        += w83l785ts.o
+obj-$(CONFIG_SENSORS_TSC210X)  += tsc210x_sensors.o
 obj-$(CONFIG_SENSORS_W83L786NG)        += w83l786ng.o
+obj-$(CONFIG_SENSORS_OMAP34XX)  += omap34xx_temp.o
 
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/hwmon/omap34xx_temp.c b/drivers/hwmon/omap34xx_temp.c
new file mode 100644 (file)
index 0000000..18e0764
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * omap34xx_temp.c - Linux kernel module for OMAP34xx hardware monitoring
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * Inspired by k8temp.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/clk.h>
+#include <linux/hrtimer.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/omap34xx.h>
+#include <mach/control.h>
+
+#define TEMP_SENSOR_SOC BIT(8)
+#define TEMP_SENSOR_EOCZ BIT(7)
+
+/* minimum delay for EOCZ rise after SOC rise is
+ * 11 cycles of the 32.768Khz clock */
+#define EOCZ_MIN_RISING_DELAY (11 * 30518)
+
+/* maximum delay for EOCZ rise after SOC rise is
+ * 14 cycles of the 32.768Khz clock */
+#define EOCZ_MAX_RISING_DELAY (14 * 30518)
+
+/* minimum delay for EOCZ falling is
+ * 36 cycles of the 32.768Khz clock */
+#define EOCZ_MIN_FALLING_DELAY (36 * 30518)
+
+/* maximum delay for EOCZ falling is
+ * 40 cycles of the 32.768Khz clock */
+#define EOCZ_MAX_FALLING_DELAY (40 * 30518)
+
+struct omap34xx_data {
+       struct device *hwmon_dev;
+       struct clk *clk_32k;
+       struct mutex update_lock;
+       const char *name;
+       char valid;
+       unsigned long last_updated;
+       u32 temp;
+};
+
+static struct platform_device omap34xx_temp_device = {
+       .name   = "omap34xx_temp",
+       .id     = -1,
+};
+
+static int adc_to_temp[] = {
+       -40, -40, -40, -40, -40, -39, -38, -36, -34, -32, -31, -29, -28, -26,
+       -25, -24, -22, -21, -19, -18, -17, -15, -14, -12, -11, -9, -8, -7, -5,
+       -4, -2, -1, 0, 1, 3, 4, 5, 7, 8, 10, 11, 13, 14, 15, 17, 18, 20, 21,
+       22, 24, 25, 27, 28, 30, 31, 32, 34, 35, 37, 38, 39, 41, 42, 44, 45,
+       47, 48, 49, 51, 52, 53, 55, 56, 58, 59, 60, 62, 63, 65, 66, 67, 69,
+       70, 72, 73, 74, 76, 77, 79, 80, 81, 83, 84, 85, 87, 88, 89, 91, 92,
+       94, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 111, 113,
+       114, 116, 117, 118, 120, 121, 122, 124, 124, 125, 125, 125, 125, 125};
+
+static inline u32 wait_for_eocz(int min_delay, int max_delay, u32 level)
+{
+       struct timespec timeout;
+       ktime_t expire;
+       u32 temp_sensor_reg;
+
+       level &= 1;
+       level *= TEMP_SENSOR_EOCZ;
+
+       expire = ktime_add_ns(ktime_get(), max_delay);
+       timeout = ns_to_timespec(min_delay);
+       hrtimer_nanosleep(&timeout, NULL, HRTIMER_MODE_REL, CLOCK_MONOTONIC);
+       do {
+               temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+               if ((temp_sensor_reg & TEMP_SENSOR_EOCZ) == level)
+                       break;
+       } while (ktime_us_delta(expire, ktime_get()) > 0);
+
+       return (temp_sensor_reg & TEMP_SENSOR_EOCZ) == level;
+}
+
+static void omap34xx_update(struct omap34xx_data *data)
+{
+       u32 temp_sensor_reg;
+
+       mutex_lock(&data->update_lock);
+
+       if (!data->valid
+           || time_after(jiffies, data->last_updated + HZ)) {
+
+               clk_enable(data->clk_32k);
+
+               temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+               temp_sensor_reg |= TEMP_SENSOR_SOC;
+               omap_ctrl_writel(temp_sensor_reg, OMAP343X_CONTROL_TEMP_SENSOR);
+
+               if (!wait_for_eocz(EOCZ_MIN_RISING_DELAY,
+                                       EOCZ_MAX_RISING_DELAY, 1))
+                       goto err;
+
+               temp_sensor_reg = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR);
+               temp_sensor_reg &= ~TEMP_SENSOR_SOC;
+               omap_ctrl_writel(temp_sensor_reg, OMAP343X_CONTROL_TEMP_SENSOR);
+
+               if (!wait_for_eocz(EOCZ_MIN_FALLING_DELAY,
+                                       EOCZ_MAX_FALLING_DELAY, 0))
+                       goto err;
+
+               data->temp = omap_ctrl_readl(OMAP343X_CONTROL_TEMP_SENSOR) &
+                                               ((1<<7) - 1);
+               data->last_updated = jiffies;
+               data->valid = 1;
+
+err:
+               clk_disable(data->clk_32k);
+       }
+
+       mutex_unlock(&data->update_lock);
+}
+
+static ssize_t show_name(struct device *dev,
+                       struct device_attribute *devattr, char *buf)
+{
+       struct omap34xx_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t show_temp_raw(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       struct omap34xx_data *data = dev_get_drvdata(dev);
+
+       omap34xx_update(data);
+
+       return sprintf(buf, "%d\n", data->temp);
+}
+
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       struct omap34xx_data *data = dev_get_drvdata(dev);
+
+       omap34xx_update(data);
+
+       return sprintf(buf, "%d\n", adc_to_temp[data->temp]);
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_input_raw, S_IRUGO, show_temp_raw,
+                               NULL, 0, 0);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __devinit omap34xx_temp_probe(void)
+{
+       int err;
+       struct omap34xx_data *data;
+
+       err = platform_device_register(&omap34xx_temp_device);
+       if (err) {
+               printk(KERN_ERR
+                       "Unable to register omap34xx temperature device\n");
+               goto exit;
+       }
+
+       data = kzalloc(sizeof(struct omap34xx_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit_platform;
+       }
+
+       dev_set_drvdata(&omap34xx_temp_device.dev, data);
+       mutex_init(&data->update_lock);
+       data->name = "omap34xx_temp";
+
+       data->clk_32k = clk_get(&omap34xx_temp_device.dev, "ts_fck");
+       if (IS_ERR(data->clk_32k)) {
+               err = PTR_ERR(data->clk_32k);
+               goto exit_free;
+       }
+
+       err = device_create_file(&omap34xx_temp_device.dev,
+                                &sensor_dev_attr_temp1_input.dev_attr);
+       if (err)
+               goto clock_free;
+
+       err = device_create_file(&omap34xx_temp_device.dev,
+                                &sensor_dev_attr_temp1_input_raw.dev_attr);
+       if (err)
+               goto exit_remove;
+
+       err = device_create_file(&omap34xx_temp_device.dev, &dev_attr_name);
+       if (err)
+               goto exit_remove_raw;
+
+       data->hwmon_dev = hwmon_device_register(&omap34xx_temp_device.dev);
+
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_all;
+       }
+
+       return 0;
+
+exit_remove_all:
+       device_remove_file(&omap34xx_temp_device.dev,
+                          &dev_attr_name);
+exit_remove_raw:
+       device_remove_file(&omap34xx_temp_device.dev,
+                          &sensor_dev_attr_temp1_input_raw.dev_attr);
+exit_remove:
+       device_remove_file(&omap34xx_temp_device.dev,
+                          &sensor_dev_attr_temp1_input.dev_attr);
+clock_free:
+       clk_put(data->clk_32k);
+
+exit_free:
+       kfree(data);
+exit_platform:
+       platform_device_unregister(&omap34xx_temp_device);
+exit:
+       return err;
+}
+
+static int __init omap34xx_temp_init(void)
+{
+       return omap34xx_temp_probe();
+}
+
+static void __exit omap34xx_temp_exit(void)
+{
+       struct omap34xx_data *data =
+                       dev_get_drvdata(&omap34xx_temp_device.dev);
+
+       clk_put(data->clk_32k);
+       hwmon_device_unregister(data->hwmon_dev);
+       device_remove_file(&omap34xx_temp_device.dev,
+                          &sensor_dev_attr_temp1_input.dev_attr);
+       device_remove_file(&omap34xx_temp_device.dev, &dev_attr_name);
+       kfree(data);
+       platform_device_unregister(&omap34xx_temp_device);
+}
+
+MODULE_AUTHOR("Peter De Schrijver");
+MODULE_DESCRIPTION("Omap34xx temperature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(omap34xx_temp_init)
+module_exit(omap34xx_temp_exit)
+
diff --git a/drivers/hwmon/tsc210x_sensors.c b/drivers/hwmon/tsc210x_sensors.c
new file mode 100644 (file)
index 0000000..daac126
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * tsc210x_sensors.c - hwmon interface to TI TSC210x sensors
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/autoconf.h>
+#ifdef CONFIG_APM
+# include <linux/apm-emulation.h>
+#endif
+
+#include <linux/spi/tsc210x.h>
+
+
+/*
+ * TI TSC210x chips include an ADC that's shared between various
+ * sensors (temperature, battery, vAUX, etc) and the touchscreen.
+ * This driver packages access to the non-touchscreen sensors
+ * available on a given board.
+ */
+
+struct tsc210x_hwmon {
+       int bat[2], aux[2], temp[2];
+
+       struct device *dev;
+       struct tsc210x_config *pdata;
+#ifdef CONFIG_APM
+       /* prevent APM from colliding with normal hwmon accessors */
+       spinlock_t apm_lock;
+#endif
+};
+
+#ifdef CONFIG_APM
+# define apm_lock(h)   spin_lock(&(h)->apm_lock)
+# define apm_unlock(h) spin_unlock(&(h)->apm_lock)
+#else
+# define apm_lock(h)   do { } while (0)
+# define apm_unlock(h) do { } while (0)
+#endif
+
+static void tsc210x_ports(void *context, int bat[], int aux[])
+{
+       struct tsc210x_hwmon    *hwmon = context;
+
+       apm_lock(hwmon);
+
+       /* FIXME for tsc2101 and tsc2111, battery voltage is:
+        *      VBAT = (5 * VREF * (bat[x])) / (2 ^ bits)
+        * For tsc2100 and tsc2102, use "6" not "5"; that formula ignores
+        * an external 100-300 Ohm resistor making the right value be just
+        * a bit over 5 (or 6).
+        *
+        * FIXME the vAUX measurements need scaling too, but in that case
+        * there's no *internal* voltage divider so just scale to VREF.
+        *
+        *  --> This code needs to know VREF, the VBAT multiplier, and
+        *      the precision.  For now, assume VREF 1.25V and 12 bits.
+        *      When an external reference is used, it normally won't
+        *      match the 1.25V (or 2.5V) values supported internally...
+        *
+        *  --> Output units should become milliVolts; currently they are
+        *      dimensionless...
+        */
+       hwmon->bat[0] = bat[0];
+       hwmon->bat[1] = bat[1];
+
+       hwmon->aux[0] = aux[0];
+       hwmon->aux[1] = aux[1];
+
+       apm_unlock(hwmon);
+}
+
+/* FIXME temp sensors also need scaling so values are milliVolts...
+ * temperature (given calibration data) should be millidegrees C.
+ */
+
+static void tsc210x_temp1(void *context, int temp)
+{
+       struct tsc210x_hwmon    *hwmon = context;
+
+       apm_lock(hwmon);
+       hwmon->temp[0] = temp;
+       apm_unlock(hwmon);
+}
+
+static void tsc210x_temp2(void *context, int temp)
+{
+       struct tsc210x_hwmon    *hwmon = context;
+
+       apm_lock(hwmon);
+       hwmon->temp[1] = temp;
+       apm_unlock(hwmon);
+}
+
+#define TSC210X_INPUT(devname, field)  \
+static ssize_t tsc_show_ ## devname(struct device *dev,        \
+               struct device_attribute *devattr, char *buf)    \
+{      \
+       struct tsc210x_hwmon *hwmon = dev_get_drvdata(dev);     \
+       return sprintf(buf, "%i\n", hwmon->field);      \
+}      \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, tsc_show_ ## devname, NULL);
+
+TSC210X_INPUT(in0, bat[0])
+TSC210X_INPUT(in1, bat[1])
+TSC210X_INPUT(in2, aux[0])
+TSC210X_INPUT(in3, aux[1])
+TSC210X_INPUT(in4, temp[0])
+TSC210X_INPUT(in5, temp[1])
+
+static ssize_t tsc_show_temp1(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       struct tsc210x_hwmon *hwmon = dev_get_drvdata(dev);
+       int t1 = hwmon->temp[0];
+       int t2 = hwmon->temp[1];
+       int diff;
+       int value;
+
+       /*
+        * Use method #2 (differential) to calculate current temperature.
+        * The difference between TEMP2 and TEMP1 input values is
+        * multiplied by a constant to obtain current temperature.
+        * To find this constant we use the values measured at 25 C as
+        * thermometer calibration data.
+        *
+        * 298150 is 25 degrees Celcius represented in Kelvins and
+        * multiplied by 1000 for fixed point precision (273.15 + 25).
+        * 273150 is zero degrees Celcius.
+        */
+       diff = hwmon->pdata->temp_at25c[1] - hwmon->pdata->temp_at25c[0];
+       value = (t2 - t1) * 298150 / diff;      /* This is in Kelvins now */
+
+       value -= 273150;                        /* Celcius millidegree */
+       return sprintf(buf, "%i\n", value);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, tsc_show_temp1, NULL);
+
+#ifdef CONFIG_APM
+static struct tsc210x_hwmon *apm_hwmon;
+
+static void tsc210x_get_power_status(struct apm_power_info *info)
+{
+       struct tsc210x_hwmon *hwmon = apm_hwmon;
+
+       apm_lock(hwmon);
+       hwmon->pdata->apm_report(info, hwmon->bat);
+       apm_unlock(hwmon);
+}
+#endif
+
+static int tsc210x_hwmon_probe(struct platform_device *pdev)
+{
+       struct tsc210x_hwmon *hwmon;
+       struct tsc210x_config *pdata = pdev->dev.platform_data;
+       int status = 0;
+
+       hwmon = (struct tsc210x_hwmon *)
+               kzalloc(sizeof(struct tsc210x_hwmon), GFP_KERNEL);
+       if (!hwmon) {
+               dev_dbg(&pdev->dev, "allocation failed\n");
+               return -ENOMEM;
+       }
+
+       hwmon->dev = hwmon_device_register(&pdev->dev);
+       if (IS_ERR(hwmon->dev)) {
+               kfree(hwmon);
+               dev_dbg(&pdev->dev, "registration failed\n");
+               return PTR_ERR(hwmon->dev);
+       }
+
+       hwmon->pdata = pdata;
+
+#ifdef CONFIG_APM
+       spin_lock_init(&hwmon->apm_lock);
+
+       if (pdata->apm_report) {
+               apm_hwmon = hwmon;
+               apm_get_power_status = tsc210x_get_power_status;
+       }
+#endif
+
+       platform_set_drvdata(pdev, hwmon);
+
+       if (pdata->monitor & (TSC_BAT1 | TSC_BAT2 | TSC_AUX1 | TSC_AUX2))
+               status |= tsc210x_ports_cb(pdev->dev.parent,
+                               tsc210x_ports, hwmon);
+       if (pdata->monitor & TSC_TEMP) {
+               status |= tsc210x_temp1_cb(pdev->dev.parent,
+                               tsc210x_temp1, hwmon);
+               status |= tsc210x_temp2_cb(pdev->dev.parent,
+                               tsc210x_temp2, hwmon);
+       }
+
+       if (status) {
+               tsc210x_ports_cb(pdev->dev.parent, NULL, NULL);
+               tsc210x_temp1_cb(pdev->dev.parent, NULL, NULL);
+               tsc210x_temp2_cb(pdev->dev.parent, NULL, NULL);
+               platform_set_drvdata(pdev, NULL);
+#ifdef CONFIG_APM
+               if (pdata->apm_report)
+                       apm_get_power_status = 0;
+#endif
+               hwmon_device_unregister(hwmon->dev);
+               kfree(hwmon);
+               return status;
+       }
+
+       if (pdata->monitor & TSC_BAT1)
+               status |= device_create_file(&pdev->dev, &dev_attr_in0_input);
+       if (pdata->monitor & TSC_BAT2)
+               status |= device_create_file(&pdev->dev, &dev_attr_in1_input);
+       if (pdata->monitor & TSC_AUX1)
+               status |= device_create_file(&pdev->dev, &dev_attr_in2_input);
+       if (pdata->monitor & TSC_AUX2)
+               status |= device_create_file(&pdev->dev, &dev_attr_in3_input);
+       if (pdata->monitor & TSC_TEMP) {
+               status |= device_create_file(&pdev->dev, &dev_attr_in4_input);
+               status |= device_create_file(&pdev->dev, &dev_attr_in5_input);
+
+               if ((pdata->temp_at25c[1] - pdata->temp_at25c[0]) == 0)
+                       dev_warn(&pdev->dev, "No temp calibration data.\n");
+               else
+                       status |= device_create_file(&pdev->dev,
+                                               &dev_attr_temp1_input);
+       }
+       if (status)     /* Not fatal */
+               dev_dbg(&pdev->dev, "Creating one or more "
+                               "attribute files failed\n");
+
+       return 0;
+}
+
+static int __exit tsc210x_hwmon_remove(struct platform_device *pdev)
+{
+       struct tsc210x_hwmon *dev = platform_get_drvdata(pdev);
+
+       tsc210x_ports_cb(pdev->dev.parent, NULL, NULL);
+       tsc210x_temp1_cb(pdev->dev.parent, NULL, NULL);
+       tsc210x_temp2_cb(pdev->dev.parent, NULL, NULL);
+       platform_set_drvdata(pdev, NULL);
+#ifdef CONFIG_APM
+       if (dev->pdata->apm_report)
+               apm_get_power_status = 0;
+#endif
+       hwmon_device_unregister(dev->dev);
+       kfree(dev);
+       return 0;
+}
+
+static struct platform_driver tsc210x_hwmon_driver = {
+       .probe          = tsc210x_hwmon_probe,
+       .remove         = __exit_p(tsc210x_hwmon_remove),
+       /* Nothing to do on suspend/resume */
+       .driver         = {
+               .name   = "tsc210x-hwmon",
+       },
+};
+
+static int __init tsc210x_hwmon_init(void)
+{
+       /* can't use driver_probe() here since the parent device
+        * gets registered "late"
+        */
+       return platform_driver_register(&tsc210x_hwmon_driver);
+}
+module_init(tsc210x_hwmon_init);
+
+static void __exit tsc210x_hwmon_exit(void)
+{
+       platform_driver_unregister(&tsc210x_hwmon_driver);
+}
+module_exit(tsc210x_hwmon_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("hwmon driver for TI TSC210x-connected sensors.");
+MODULE_LICENSE("GPL");
index 711ca08ab7762ab19f6516c9a5ba24bedcf54c4e..f1e6aa7b93bbb9ae8e9e57d8e6eed9f1d8f94193 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig I2C
        tristate "I2C support"
        depends on HAS_IOMEM
+       default y if MACH_OMAP_H3 || MACH_OMAP_OSK
        ---help---
          I2C (pronounce: I-square-C) is a slow serial bus protocol used in
          many micro controller applications and developed by Philips.  SMBus,
index 6ee997b2817c450b3ac2fae2bf32e5ad035ff5d3..eb94378cab7590e9aa78e4c71e4b8baf2251df55 100644 (file)
@@ -403,10 +403,26 @@ config I2C_OMAP
        default y if MACH_OMAP_H3 || MACH_OMAP_OSK
        help
          If you say yes to this option, support will be included for the
-         I2C interface on the Texas Instruments OMAP1/2 family of processors.
-         Like OMAP1510/1610/1710/5912 and OMAP242x.
+         I2C interface on the Texas Instruments OMAP1/2/3 family of
+         processors.
+         Like OMAP1510/1610/1710/5912, OMAP242x, OMAP34x and OMAP35x.
          For details see http://www.ti.com/omap.
 
+config I2C2_OMAP_BEAGLE
+       bool "Enable I2C2 for OMAP3 BeagleBoard"
+       depends on ARCH_OMAP && MACH_OMAP3_BEAGLE
+       select OMAP_MUX
+       default n
+       help
+         Say Y here if you want to enable I2C bus 2 at OMAP3 based
+         BeagleBoard.
+         I2C2 at BeagleBoard is connected to expansion connector, i.e. unused
+         if nothing is connected to this connector. As internal OMAP3 pull up
+         resistors are not strong enough, enabled but unused I2C2 bus results
+         in error messages (e.g. I2C timeouts). Enable this only if you have
+         something connected to I2C2 at board's expansion connector and this
+         extension has additional pull up resistors for I2C2 bus.
+
 config I2C_PASEMI
        tristate "PA Semi SMBus interface"
        depends on PPC_PASEMI && PCI
index 97dbfa2107fee2fe7b7170219c9aebf552b8381b..d4dc22da8cc7b9fccbbaefe82db7c8fcec05c512 100644 (file)
@@ -66,6 +66,7 @@ obj-$(CONFIG_I2C_SIBYTE)      += i2c-sibyte.o
 obj-$(CONFIG_I2C_STUB)         += i2c-stub.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 e7eb7bf9ddecc762e088d17f155c5b38818c6a57..1e6c3fd987969d63b7a9e3d2fb778d851bcdbecb 100644 (file)
@@ -2,13 +2,16 @@
  * TI OMAP I2C master mode driver
  *
  * Copyright (C) 2003 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- *
- * Updated to work with multiple I2C interfaces on 24xx by
- * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
  * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
  *
- * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ *     Tony Lindgren <tony@atomide.com>
+ *     Imre Deak <imre.deak@nokia.com>
+ *     Juha Yrjölä <juha.yrjola@solidboot.com>
+ *     Syed Khasim <x0khasim@ti.com>
+ *     Nishant Menon <nm@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
@@ -33,8 +36,7 @@
 #include <linux/completion.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
 
 /* timeout waiting for the controller to respond */
 #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
 #define OMAP_I2C_SCLL_REG              0x34
 #define OMAP_I2C_SCLH_REG              0x38
 #define OMAP_I2C_SYSTEST_REG           0x3c
+#define OMAP_I2C_BUFSTAT_REG           0x40
 
 /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR                (1 << 14)       /* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR                (1 << 13)       /* RX Buffer drain int enable */
 #define OMAP_I2C_IE_XRDY       (1 << 4)        /* TX data ready int enable */
 #define OMAP_I2C_IE_RRDY       (1 << 3)        /* RX data ready int enable */
 #define OMAP_I2C_IE_ARDY       (1 << 2)        /* Access ready int enable */
@@ -64,7 +69,8 @@
 #define OMAP_I2C_IE_AL         (1 << 0)        /* Arbitration lost int ena */
 
 /* I2C Status Register (OMAP_I2C_STAT): */
-#define OMAP_I2C_STAT_SBD      (1 << 15)       /* Single byte data */
+#define OMAP_I2C_STAT_XDR      (1 << 14)       /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR      (1 << 13)       /* RX Buffer draining */
 #define OMAP_I2C_STAT_BB       (1 << 12)       /* Bus busy */
 #define OMAP_I2C_STAT_ROVR     (1 << 11)       /* Receive overrun */
 #define OMAP_I2C_STAT_XUDF     (1 << 10)       /* Transmit underflow */
 
 /* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
 #define OMAP_I2C_BUF_RDMA_EN   (1 << 15)       /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14)       /* RX FIFO Clear */
 #define OMAP_I2C_BUF_XDMA_EN   (1 << 7)        /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6)        /* TX FIFO Clear */
 
 /* I2C Configuration Register (OMAP_I2C_CON): */
 #define OMAP_I2C_CON_EN                (1 << 15)       /* I2C module enable */
 #define OMAP_I2C_CON_BE                (1 << 14)       /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12)       /* High Speed support */
 #define OMAP_I2C_CON_STB       (1 << 11)       /* Start byte mode (master) */
 #define OMAP_I2C_CON_MST       (1 << 10)       /* Master/slave mode */
 #define OMAP_I2C_CON_TRX       (1 << 9)        /* TX/RX mode (master only) */
 #define OMAP_I2C_CON_STP       (1 << 1)        /* Stop cond (master only) */
 #define OMAP_I2C_CON_STT       (1 << 0)        /* Start condition (master) */
 
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL   8
+#define OMAP_I2C_SCLH_HSSCLH   8
+
 /* I2C System Test Register (OMAP_I2C_SYSTEST): */
 #ifdef DEBUG
 #define OMAP_I2C_SYSTEST_ST_EN         (1 << 15)       /* System test enable */
 /* I2C System Configuration Register (OMAP_I2C_SYSC): */
 #define OMAP_I2C_SYSC_SRST             (1 << 1)        /* Soft Reset */
 
-/* REVISIT: Use platform_data instead of module parameters */
-/* Fast Mode = 400 kHz, Standard = 100 kHz */
-static int clock = 100; /* Default: 100 kHz */
-module_param(clock, int, 0);
-MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
-
 struct omap_i2c_dev {
        struct device           *dev;
        void __iomem            *base;          /* virtual */
@@ -123,11 +130,17 @@ struct omap_i2c_dev {
        struct clk              *fclk;          /* Functional clock */
        struct completion       cmd_complete;
        struct resource         *ioarea;
+       u32                     speed;          /* Speed of bus in Khz */
        u16                     cmd_err;
        u8                      *buf;
        size_t                  buf_len;
        struct i2c_adapter      adapter;
+       u8                      fifo_size;      /* use as flag and value
+                                                * fifo_size==0 implies no fifo
+                                                * if set, should be trsh+1
+                                                */
        unsigned                rev1:1;
+       unsigned                b_hw:1;         /* bad h/w fixes */
        unsigned                idle:1;
        u16                     iestate;        /* Saved interrupt register */
 };
@@ -143,26 +156,37 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
        return __raw_readw(i2c_dev->base + reg);
 }
 
-static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
 {
-       if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+       if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
                dev->iclk = clk_get(dev->dev, "i2c_ick");
                if (IS_ERR(dev->iclk)) {
                        dev->iclk = NULL;
                        return -ENODEV;
                }
        }
-
-       dev->fclk = clk_get(dev->dev, "i2c_fck");
-       if (IS_ERR(dev->fclk)) {
-               if (dev->iclk != NULL) {
-                       clk_put(dev->iclk);
-                       dev->iclk = NULL;
+       /* For I2C operations on 2430 we need 96Mhz clock */
+       if (cpu_is_omap2430()) {
+               dev->fclk = clk_get(dev->dev, "i2chs_fck");
+               if (IS_ERR(dev->fclk)) {
+                       if (dev->iclk != NULL) {
+                               clk_put(dev->iclk);
+                               dev->iclk = NULL;
+                       }
+                       dev->fclk = NULL;
+                       return -ENODEV;
+               }
+       } else {
+               dev->fclk = clk_get(dev->dev, "i2c_fck");
+               if (IS_ERR(dev->fclk)) {
+                       if (dev->iclk != NULL) {
+                               clk_put(dev->iclk);
+                               dev->iclk = NULL;
+                       }
+                       dev->fclk = NULL;
+                       return -ENODEV;
                }
-               dev->fclk = NULL;
-               return -ENODEV;
        }
-
        return 0;
 }
 
@@ -181,22 +205,28 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev)
        if (dev->iclk != NULL)
                clk_enable(dev->iclk);
        clk_enable(dev->fclk);
+       dev->idle = 0;
        if (dev->iestate)
                omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
-       dev->idle = 0;
 }
 
 static void omap_i2c_idle(struct omap_i2c_dev *dev)
 {
        u16 iv;
 
-       dev->idle = 1;
        dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
        if (dev->rev1)
-               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);   /* Read clears */
+               iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
        else
                omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
+       /*
+        * The wmb() is to ensure that the I2C interrupt mask write
+        * reaches the I2C controller before the dev->idle store
+        * occurs.
+        */
+       wmb();
+       dev->idle = 1;
        clk_disable(dev->fclk);
        if (dev->iclk != NULL)
                clk_disable(dev->iclk);
@@ -204,9 +234,11 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
 
 static int omap_i2c_init(struct omap_i2c_dev *dev)
 {
-       u16 psc = 0;
+       u16 psc = 0, scll = 0, sclh = 0;
+       u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
        unsigned long fclk_rate = 12000000;
        unsigned long timeout;
+       unsigned long internal_clk = 0;
 
        if (!dev->rev1) {
                omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
@@ -249,27 +281,65 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
                        psc = fclk_rate / 12000000;
        }
 
+       if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+
+               /* HSI2C controller internal clk rate should be 19.2 Mhz */
+               internal_clk = 19200;
+               fclk_rate = clk_get_rate(dev->fclk) / 1000;
+
+               /* Compute prescaler divisor */
+               psc = fclk_rate / internal_clk;
+               psc = psc - 1;
+
+               /* If configured for High Speed */
+               if (dev->speed > 400) {
+                       /* For first phase of HS mode */
+                       fsscll = internal_clk / (400 * 2) - 6;
+                       fssclh = internal_clk / (400 * 2) - 6;
+
+                       /* For second phase of HS mode */
+                       hsscll = fclk_rate / (dev->speed * 2) - 6;
+                       hssclh = fclk_rate / (dev->speed * 2) - 6;
+               } else {
+                       /* To handle F/S modes */
+                       fsscll = internal_clk / (dev->speed * 2) - 6;
+                       fssclh = internal_clk / (dev->speed * 2) - 6;
+               }
+               scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+               sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+       } else {
+               /* Program desired operating rate */
+               fclk_rate /= (psc + 1) * 1000;
+               if (psc > 2)
+                       psc = 2;
+               scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+               sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+       }
+
        /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
        omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
 
-       /* Program desired operating rate */
-       fclk_rate /= (psc + 1) * 1000;
-       if (psc > 2)
-               psc = 2;
+       /* SCL low and high time values */
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
 
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
-                          fclk_rate / (clock * 2) - 7 + psc);
-       omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
-                          fclk_rate / (clock * 2) - 7 + psc);
+       if (dev->fifo_size)
+               /* Note: setup required fifo size - 1 */
+               omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+                                       (dev->fifo_size - 1) << 8 | /* RTRSH */
+                                       OMAP_I2C_BUF_RXFIF_CLR |
+                                       (dev->fifo_size - 1) | /* XTRSH */
+                                       OMAP_I2C_BUF_TXFIF_CLR);
 
        /* Take the I2C module out of reset: */
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 
        /* Enable interrupts */
        omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
-                          (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
-                           OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
-                           OMAP_I2C_IE_AL));
+                       (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+                       OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+                       OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
+                               (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0));
        return 0;
 }
 
@@ -316,20 +386,54 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
 
        omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
 
+       /* Clear the FIFO Buffers */
+       w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+       w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+       omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
        init_completion(&dev->cmd_complete);
        dev->cmd_err = 0;
 
        w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+       /* High speed configuration */
+       if (dev->speed > 400)
+               w |= OMAP_I2C_CON_OPMODE_HS;
+
        if (msg->flags & I2C_M_TEN)
                w |= OMAP_I2C_CON_XA;
        if (!(msg->flags & I2C_M_RD))
                w |= OMAP_I2C_CON_TRX;
-       if (stop)
+
+       if (!dev->b_hw && stop)
                w |= OMAP_I2C_CON_STP;
+
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
 
-       r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
-                                                     OMAP_I2C_TIMEOUT);
+       /*
+        * Don't write stt and stp together on some hardware
+        */
+       if (dev->b_hw && stop) {
+               unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+               u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+               while (con & OMAP_I2C_CON_STT) {
+                       con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+
+                       /* Let the user know if i2c is in a bad state */
+                       if (time_after(jiffies, delay)) {
+                               dev_err(dev->dev, "controller timed out "
+                               "waiting for start condition to finish\n");
+                               return -ETIMEDOUT;
+                       }
+                       cpu_relax();
+               }
+
+               w |= OMAP_I2C_CON_STP;
+               w &= ~OMAP_I2C_CON_STT;
+               omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+       }
+       r = wait_for_completion_timeout(&dev->cmd_complete,
+                                       OMAP_I2C_TIMEOUT);
        dev->buf_len = 0;
        if (r < 0)
                return r;
@@ -376,7 +480,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
        omap_i2c_unidle(dev);
 
-       if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+       r = omap_i2c_wait_for_bb(dev);
+       if (r < 0)
                goto out;
 
        for (i = 0; i < num; i++) {
@@ -411,6 +516,9 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
        omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
 }
 
+/* rev1 devices are apparently only on some 15xx */
+#ifdef CONFIG_ARCH_OMAP15XX
+
 static irqreturn_t
 omap_i2c_rev1_isr(int this_irq, void *dev_id)
 {
@@ -465,6 +573,9 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
 
        return IRQ_HANDLED;
 }
+#else
+#define omap_i2c_rev1_isr              0
+#endif
 
 static irqreturn_t
 omap_i2c_isr(int this_irq, void *dev_id)
@@ -472,7 +583,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
        struct omap_i2c_dev *dev = dev_id;
        u16 bits;
        u16 stat, w;
-       int count = 0;
+       int err, count = 0;
 
        if (dev->idle)
                return IRQ_NONE;
@@ -487,39 +598,96 @@ omap_i2c_isr(int this_irq, void *dev_id)
 
                omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
 
-               if (stat & OMAP_I2C_STAT_ARDY) {
-                       omap_i2c_complete_cmd(dev, 0);
-                       continue;
+               err = 0;
+               if (stat & OMAP_I2C_STAT_NACK) {
+                       err |= OMAP_I2C_STAT_NACK;
+                       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+                                          OMAP_I2C_CON_STP);
                }
-               if (stat & OMAP_I2C_STAT_RRDY) {
-                       w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
-                       if (dev->buf_len) {
-                               *dev->buf++ = w;
-                               dev->buf_len--;
+               if (stat & OMAP_I2C_STAT_AL) {
+                       dev_err(dev->dev, "Arbitration lost\n");
+                       err |= OMAP_I2C_STAT_AL;
+               }
+               if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+                                       OMAP_I2C_STAT_AL))
+                       omap_i2c_complete_cmd(dev, err);
+               if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+                       u8 num_bytes = 1;
+                       if (dev->fifo_size) {
+                               if (stat & OMAP_I2C_STAT_RRDY)
+                                       num_bytes = dev->fifo_size;
+                               else
+                                       num_bytes = omap_i2c_read_reg(dev,
+                                                       OMAP_I2C_BUFSTAT_REG);
+                       }
+                       while (num_bytes) {
+                               num_bytes--;
+                               w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
                                if (dev->buf_len) {
-                                       *dev->buf++ = w >> 8;
+                                       *dev->buf++ = w;
                                        dev->buf_len--;
+                                       /* Data reg from 2430 is 8 bit wide */
+                                       if (!cpu_is_omap2430() &&
+                                                       !cpu_is_omap34xx()) {
+                                               if (dev->buf_len) {
+                                                       *dev->buf++ = w >> 8;
+                                                       dev->buf_len--;
+                                               }
+                                       }
+                               } else {
+                                       if (stat & OMAP_I2C_STAT_RRDY)
+                                               dev_err(dev->dev,
+                                                       "RRDY IRQ while no data"
+                                                               " requested\n");
+                                       if (stat & OMAP_I2C_STAT_RDR)
+                                               dev_err(dev->dev,
+                                                       "RDR IRQ while no data"
+                                                               " requested\n");
+                                       break;
                                }
-                       } else
-                               dev_err(dev->dev, "RRDY IRQ while no data "
-                                               "requested\n");
-                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+                       }
+                       omap_i2c_ack_stat(dev,
+                               stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
                        continue;
                }
-               if (stat & OMAP_I2C_STAT_XRDY) {
-                       w = 0;
-                       if (dev->buf_len) {
-                               w = *dev->buf++;
-                               dev->buf_len--;
+               if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+                       u8 num_bytes = 1;
+                       if (dev->fifo_size) {
+                               if (stat & OMAP_I2C_STAT_XRDY)
+                                       num_bytes = dev->fifo_size;
+                               else
+                                       num_bytes = omap_i2c_read_reg(dev,
+                                                       OMAP_I2C_BUFSTAT_REG);
+                       }
+                       while (num_bytes) {
+                               num_bytes--;
+                               w = 0;
                                if (dev->buf_len) {
-                                       w |= *dev->buf++ << 8;
+                                       w = *dev->buf++;
                                        dev->buf_len--;
+                                       /* Data reg from  2430 is 8 bit wide */
+                                       if (!cpu_is_omap2430() &&
+                                                       !cpu_is_omap34xx()) {
+                                               if (dev->buf_len) {
+                                                       w |= *dev->buf++ << 8;
+                                                       dev->buf_len--;
+                                               }
+                                       }
+                               } else {
+                                       if (stat & OMAP_I2C_STAT_XRDY)
+                                               dev_err(dev->dev,
+                                                       "XRDY IRQ while no "
+                                                       "data to send\n");
+                                       if (stat & OMAP_I2C_STAT_XDR)
+                                               dev_err(dev->dev,
+                                                       "XDR IRQ while no "
+                                                       "data to send\n");
+                                       break;
                                }
-                       } else
-                               dev_err(dev->dev, "XRDY IRQ while no "
-                                       "data to send\n");
-                       omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
-                       omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+                               omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+                       }
+                       omap_i2c_ack_stat(dev,
+                               stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
                        continue;
                }
                if (stat & OMAP_I2C_STAT_ROVR) {
@@ -527,18 +695,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
                        dev->cmd_err |= OMAP_I2C_STAT_ROVR;
                }
                if (stat & OMAP_I2C_STAT_XUDF) {
-                       dev_err(dev->dev, "Transmit overflow\n");
+                       dev_err(dev->dev, "Transmit underflow\n");
                        dev->cmd_err |= OMAP_I2C_STAT_XUDF;
                }
-               if (stat & OMAP_I2C_STAT_NACK) {
-                       omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
-                       omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
-                                          OMAP_I2C_CON_STP);
-               }
-               if (stat & OMAP_I2C_STAT_AL) {
-                       dev_err(dev->dev, "Arbitration lost\n");
-                       omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
-               }
        }
 
        return count ? IRQ_HANDLED : IRQ_NONE;
@@ -549,13 +708,14 @@ static const struct i2c_algorithm omap_i2c_algo = {
        .functionality  = omap_i2c_func,
 };
 
-static int
+static int __init
 omap_i2c_probe(struct platform_device *pdev)
 {
        struct omap_i2c_dev     *dev;
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
        int r;
+       u32 *speed = NULL;
 
        /* NOTE: driver uses the static register mapping */
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -576,30 +736,53 @@ omap_i2c_probe(struct platform_device *pdev)
                return -EBUSY;
        }
 
-       if (clock > 200)
-               clock = 400;    /* Fast mode */
-       else
-               clock = 100;    /* Standard mode */
-
        dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
        if (!dev) {
                r = -ENOMEM;
                goto err_release_region;
        }
 
+       if (pdev->dev.platform_data != NULL)
+               speed = (u32 *) pdev->dev.platform_data;
+       else
+               *speed = 100; /* Defualt speed */
+
+       dev->speed = *speed;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
-       dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+       dev->base = ioremap(mem->start, mem->end - mem->start + 1);
+       if (!dev->base) {
+               r = -ENOMEM;
+               goto err_free_mem;
+       }
+
        platform_set_drvdata(pdev, dev);
 
-       if ((r = omap_i2c_get_clocks(dev)) != 0)
-               goto err_free_mem;
+       r = omap_i2c_get_clocks(dev);
+       if (r != 0)
+               goto err_iounmap;
 
        omap_i2c_unidle(dev);
 
        if (cpu_is_omap15xx())
                dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
 
+       if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+               u16 s;
+
+               /* Set up the fifo size - Get total size */
+               s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+               dev->fifo_size = 0x8 << s;
+
+               /*
+                * Set up notification threshold as half the total available
+                * size. This is to ensure that we can handle the status on int
+                * call back latencies.
+                */
+               dev->fifo_size = (dev->fifo_size / 2);
+               dev->b_hw = 1; /* Enable hardware fixes */
+       }
+
        /* reset ASAP, clearing any IRQs */
        omap_i2c_init(dev);
 
@@ -612,7 +795,7 @@ omap_i2c_probe(struct platform_device *pdev)
        }
        r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
        dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
-                pdev->id, r >> 4, r & 0xf, clock);
+                pdev->id, r >> 4, r & 0xf, dev->speed);
 
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
@@ -640,6 +823,8 @@ err_unuse_clocks:
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_idle(dev);
        omap_i2c_put_clocks(dev);
+err_iounmap:
+       iounmap(dev->base);
 err_free_mem:
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
@@ -661,6 +846,7 @@ omap_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&dev->adapter);
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
        omap_i2c_put_clocks(dev);
+       iounmap(dev->base);
        kfree(dev);
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(mem->start, (mem->end - mem->start) + 1);
@@ -677,14 +863,14 @@ static struct platform_driver omap_i2c_driver = {
 };
 
 /* I2C may be needed to bring up other drivers */
-static int __init
+static int __devinit
 omap_i2c_init_driver(void)
 {
        return platform_driver_register(&omap_i2c_driver);
 }
 subsys_initcall(omap_i2c_init_driver);
 
-static void __exit omap_i2c_exit_driver(void)
+static void __devexit omap_i2c_exit_driver(void)
 {
        platform_driver_unregister(&omap_i2c_driver);
 }
index a95cb9465d656949bed4429279a75c35fb547b23..d803c412fa6dbe829eb4a20949ab3e8da97e47cc 100644 (file)
@@ -137,6 +137,53 @@ 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 TWL4030_MADC
+       tristate "TWL4030 MADC Driver"
+       depends on TWL4030_CORE
+       help
+         The TWL4030 Monitoring ADC driver enables the host
+         processor to monitor analog signals using analog-to-digital
+         conversions on the input source. TWL4030 MADC provides the
+         following features:
+          - Single 10-bit ADC with successive approximation register (SAR) conversion;
+          - Analog multiplexer for 16 inputs;
+          - Seven (of the 16) inputs are freely available;
+          - Battery voltage monitoring;
+          - Concurrent conversion request management;
+          - Interrupt signal to Primary Interrupt Handler;
+          - Averaging feature;
+          - Selective enable/disable of the averaging feature.
+
+         Say 'y' here to statically link this module into the kernel or 'm'
+         to build it as a dinamically loadable module. The module will be
+         called twl4030-madc.ko
+
+config TWL4030_USB
+       tristate "TWL4030 USB Transceiver Driver"
+       depends on TWL4030_CORE
+
+config TWL4030_PWRBUTTON
+       tristate "TWL4030 Power button Driver"
+       depends on TWL4030_CORE
+
+config TWL4030_POWEROFF
+       tristate "TWL4030 device poweroff"
+       depends on TWL4030_CORE
+
 config SENSORS_MAX6875
        tristate "Maxim MAX6875 Power supply supervisor"
        depends on EXPERIMENTAL
@@ -162,6 +209,23 @@ config SENSORS_TSL2550
          This driver can also be built as a module.  If so, the module
          will be called tsl2550.
 
+config SENSORS_TSL2563
+       tristate "Taos TSL2563 ambient light sensor"
+       depends on I2C && HWMON
+       help
+         If you say yes here you get support for the Taos TSL2563
+         ambient light sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tsl2563.
+
+config LP5521
+       tristate "LP5521 LED driver chip"
+       depends on I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LP5521 LED driver.
+
 config MENELAUS
        bool "TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP24XX
index 39e3e69ed1256bf93de0be16b9687bd15eb8e4a9..ba41a574576b41d46bf5b100702bab7ad954b36f 100644 (file)
@@ -19,10 +19,19 @@ obj-$(CONFIG_PCF8575)               += pcf8575.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_SENSORS_TSL2550)  += tsl2550.o
+obj-$(CONFIG_SENSORS_TSL2563)  += tsl2563.o
+obj-$(CONFIG_TWL4030_CORE)     += twl4030-pwrirq.o twl4030-power.o
+obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
+obj-$(CONFIG_TWL4030_POWEROFF) += twl4030-poweroff.o
+obj-$(CONFIG_TWL4030_PWRBUTTON)        += twl4030-pwrbutton.o
+obj-$(CONFIG_TWL4030_MADC)     += twl4030-madc.o
+obj-$(CONFIG_RTC_X1205_I2C)    += x1205.o
+obj-$(CONFIG_LP5521)           += lp5521.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-
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..dfe7f04
--- /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(1);
+       if (!adap)
+               return -ENODEV;
+       msg->addr = addr;       /* I2C address of GPIO EXPA */
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       data[0] = val;
+       err = i2c_transfer(adap, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+/* Read from I/O EXPANDER on the H3 board.
+ * The IO expanders need an independent I2C client driver.
+ */
+
+int read_gpio_expa(u8 * val, int addr)
+{
+       struct i2c_adapter *adap;
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       adap = i2c_get_adapter(1);
+       if (!adap)
+               return -ENODEV;
+       msg->addr = addr;       /* I2C address of GPIO EXPA */
+       msg->flags = I2C_M_RD;
+       msg->len = 2;
+       msg->buf = data;
+       err = i2c_transfer(adap, msg, 1);
+       *val = data[0];
+
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+EXPORT_SYMBOL(read_gpio_expa);
+EXPORT_SYMBOL(write_gpio_expa);
+
index 4655b794ebe3c7d06ad911cf898c25a5061b03d0..f717270993318ad8b47f6aba9861157f13c11d27 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/usb/otg.h>
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
 #include <mach/usb.h>
@@ -49,10 +50,9 @@ MODULE_LICENSE("GPL");
 
 struct isp1301 {
        struct otg_transceiver  otg;
-       struct i2c_client       client;
+       struct i2c_client       *client;
        void                    (*i2c_release)(struct device *dev);
 
-       int                     irq;
        int                     irq_type;
 
        u32                     last_otg_ctrl;
@@ -138,14 +138,6 @@ static inline void notresponding(struct isp1301 *isp)
 
 /*-------------------------------------------------------------------------*/
 
-/* only two addresses possible */
-#define        ISP_BASE                0x2c
-static unsigned short normal_i2c[] = {
-       ISP_BASE, ISP_BASE + 1,
-       I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct i2c_driver isp1301_driver;
 
 /* smbus apis are used for portability */
@@ -153,25 +145,25 @@ static struct i2c_driver isp1301_driver;
 static inline u8
 isp1301_get_u8(struct isp1301 *isp, u8 reg)
 {
-       return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+       return i2c_smbus_read_byte_data(isp->client, reg + 0);
 }
 
 static inline int
 isp1301_get_u16(struct isp1301 *isp, u8 reg)
 {
-       return i2c_smbus_read_word_data(&isp->client, reg);
+       return i2c_smbus_read_word_data(isp->client, reg);
 }
 
 static inline int
 isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-       return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+       return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
 }
 
 static inline int
 isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
 {
-       return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+       return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -349,10 +341,10 @@ isp1301_defer_work(struct isp1301 *isp, int work)
        int status;
 
        if (isp && !test_and_set_bit(work, &isp->todo)) {
-               (void) get_device(&isp->client.dev);
+               (void) get_device(&isp->client->dev);
                status = schedule_work(&isp->work);
                if (!status && !isp->working)
-                       dev_vdbg(&isp->client.dev,
+                       dev_vdbg(&isp->client->dev,
                                "work item %d may be lost\n", work);
        }
 }
@@ -1135,7 +1127,7 @@ isp1301_work(struct work_struct *work)
                /* transfer state from otg engine to isp1301 */
                if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
                        otg_update_isp(isp);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 #endif
                /* transfer state from isp1301 to otg engine */
@@ -1143,7 +1135,7 @@ isp1301_work(struct work_struct *work)
                        u8              stat = isp1301_clear_latch(isp);
 
                        isp_update_otg(isp, stat);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
@@ -1178,7 +1170,7 @@ isp1301_work(struct work_struct *work)
                        }
                        host_resume(isp);
                        // mdelay(10);
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
@@ -1187,15 +1179,15 @@ isp1301_work(struct work_struct *work)
                        if (!stop)
                                mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
 #endif
-                       put_device(&isp->client.dev);
+                       put_device(&isp->client->dev);
                }
 
                if (isp->todo)
-                       dev_vdbg(&isp->client.dev,
+                       dev_vdbg(&isp->client->dev,
                                "work done, todo = 0x%lx\n",
                                isp->todo);
                if (stop) {
-                       dev_dbg(&isp->client.dev, "stop\n");
+                       dev_dbg(&isp->client->dev, "stop\n");
                        break;
                }
        } while (isp->todo);
@@ -1219,7 +1211,7 @@ static void isp1301_release(struct device *dev)
 {
        struct isp1301  *isp;
 
-       isp = container_of(dev, struct isp1301, client.dev);
+       isp = dev_get_drvdata(dev);
 
        /* ugly -- i2c hijacks our memory hook to wait_for_completion() */
        if (isp->i2c_release)
@@ -1229,15 +1221,15 @@ static void isp1301_release(struct device *dev)
 
 static struct isp1301 *the_transceiver;
 
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *i2c)
 {
        struct isp1301  *isp;
 
-       isp = container_of(i2c, struct isp1301, client);
+       isp = i2c_get_clientdata(i2c);
 
        isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
        isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
-       free_irq(isp->irq, isp);
+       free_irq(i2c->irq, isp);
 #ifdef CONFIG_USB_OTG
        otg_unbind(isp);
 #endif
@@ -1252,7 +1244,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
        put_device(&i2c->dev);
        the_transceiver = 0;
 
-       return i2c_detach_client(i2c);
+       return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1285,7 +1277,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
                INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 
-       dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+       dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
 
        return 0;
 }
@@ -1310,7 +1302,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
 
 #ifdef CONFIG_USB_OTG
        isp->otg.host = host;
-       dev_dbg(&isp->client.dev, "registered host\n");
+       dev_dbg(&isp->client->dev, "registered host\n");
        host_suspend(isp);
        if (isp->otg.gadget)
                return isp1301_otg_enable(isp);
@@ -1325,7 +1317,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
        if (machine_is_omap_h2())
                isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
-       dev_info(&isp->client.dev, "A-Host sessions ok\n");
+       dev_info(&isp->client->dev, "A-Host sessions ok\n");
        isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
                INTR_ID_GND);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
@@ -1343,7 +1335,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
        return 0;
 
 #else
-       dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+       dev_dbg(&isp->client->dev, "host sessions not allowed\n");
        return -EINVAL;
 #endif
 
@@ -1370,7 +1362,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
 
 #ifdef CONFIG_USB_OTG
        isp->otg.gadget = gadget;
-       dev_dbg(&isp->client.dev, "registered gadget\n");
+       dev_dbg(&isp->client->dev, "registered gadget\n");
        /* gadget driver may be suspended until vbus_connect () */
        if (isp->otg.host)
                return isp1301_otg_enable(isp);
@@ -1395,7 +1387,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
                INTR_SESS_VLD);
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
                INTR_VBUS_VLD);
-       dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+       dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
        dump_regs(isp, __func__);
 
        /* If this has a Mini-AB connector, this mode is highly
@@ -1408,7 +1400,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
        return 0;
 
 #else
-       dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+       dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
        return -EINVAL;
 #endif
 }
@@ -1508,12 +1500,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
 
 /*-------------------------------------------------------------------------*/
 
-/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *i2c)
 {
        int                     status;
        struct isp1301          *isp;
-       struct i2c_client       *i2c;
 
        if (the_transceiver)
                return 0;
@@ -1527,37 +1517,19 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
        isp->timer.function = isp1301_timer;
        isp->timer.data = (unsigned long) isp;
 
-       isp->irq = -1;
-       isp->client.addr = address;
-       i2c_set_clientdata(&isp->client, isp);
-       isp->client.adapter = bus;
-       isp->client.driver = &isp1301_driver;
-       strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-       i2c = &isp->client;
-
-       /* if this is a true probe, verify the chip ... */
-       if (kind < 0) {
-               status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
-               if (status != I2C_VENDOR_ID_PHILIPS) {
-                       dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
-                               address, status);
-                       goto fail1;
-               }
-               status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
-               if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
-                       dev_dbg(&bus->dev, "%d not isp1301, %d\n",
-                               address, status);
-                       goto fail1;
-               }
-       }
+       i2c_set_clientdata(i2c, isp);
+       isp->client = i2c;
 
-       status = i2c_attach_client(i2c);
-       if (status < 0) {
-               dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
-                               DRIVER_NAME, address, status);
-fail1:
-               kfree(isp);
-               return 0;
+       /* verify the chip (shouldn't be necesary) */
+       status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+       if (status != I2C_VENDOR_ID_PHILIPS) {
+               dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+               goto fail;
+       }
+       status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+       if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+               dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+               goto fail;
        }
        isp->i2c_release = i2c->dev.release;
        i2c->dev.release = isp1301_release;
@@ -1586,7 +1558,7 @@ fail1:
        status = otg_bind(isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't bind OTG\n");
-               goto fail2;
+               goto fail;
        }
 #endif
 
@@ -1599,26 +1571,21 @@ fail1:
 
                /* IRQ wired at M14 */
                omap_cfg_reg(M14_1510_GPIO2);
-               isp->irq = OMAP_GPIO_IRQ(2);
                if (gpio_request(2, "isp1301") == 0)
                        gpio_direction_input(2);
                isp->irq_type = IRQF_TRIGGER_FALLING;
        }
 
        isp->irq_type |= IRQF_SAMPLE_RANDOM;
-       status = request_irq(isp->irq, isp1301_irq,
+       status = request_irq(i2c->irq, isp1301_irq,
                        isp->irq_type, DRIVER_NAME, isp);
        if (status < 0) {
                dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
-                               isp->irq, status);
-#ifdef CONFIG_USB_OTG
-fail2:
-#endif
-               i2c_detach_client(i2c);
-               goto fail1;
+                               i2c->irq, status);
+               goto fail;
        }
 
-       isp->otg.dev = &isp->client.dev;
+       isp->otg.dev = &i2c->dev;
        isp->otg.label = DRIVER_NAME;
 
        isp->otg.set_host = isp1301_set_host,
@@ -1649,22 +1616,25 @@ fail2:
                        status);
 
        return 0;
-}
 
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
-       if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
-                       | I2C_FUNC_SMBUS_READ_WORD_DATA))
-               return -EINVAL;
-       return i2c_probe(bus, &addr_data, isp1301_probe);
+fail:
+       kfree(isp);
+       return -ENODEV;
 }
 
+static const struct i2c_device_id isp1301_id[] = {
+       { "isp1301_omap", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
 static struct i2c_driver isp1301_driver = {
        .driver = {
                .name   = "isp1301_omap",
        },
-       .attach_adapter = isp1301_scan_bus,
-       .detach_client  = isp1301_detach_client,
+       .probe          = isp1301_probe,
+       .remove         = __exit_p(isp1301_remove),
+       .id_table       = isp1301_id,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/lp5521.c b/drivers/i2c/chips/lp5521.c
new file mode 100644 (file)
index 0000000..c0862d9
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * drivers/i2c/chips/lp5521.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Written by Mathias Nyman <mathias.nyman@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <mach/gpio.h>
+
+#define LP5521_DRIVER_NAME             "lp5521"
+
+#ifdef LED_CONNECTED_WRONG
+#define LP5521_REG_R_PWM               0x04
+#define LP5521_REG_B_PWM               0x02
+#else
+#define LP5521_REG_R_PWM               0x02
+#define LP5521_REG_B_PWM               0x04
+#endif
+#define LP5521_REG_ENABLE              0x00
+#define LP5521_REG_OP_MODE             0x01
+#define LP5521_REG_G_PWM               0x03
+#define LP5521_REG_R_CNTRL             0x05
+#define LP5521_REG_G_CNTRL             0x06
+#define LP5521_REG_B_CNTRL             0x07
+#define LP5521_REG_MISC                        0x08
+#define LP5521_REG_R_CHANNEL_PC                0x09
+#define LP5521_REG_G_CHANNEL_PC                0x0a
+#define LP5521_REG_B_CHANNEL_PC                0x0b
+#define LP5521_REG_STATUS              0x0c
+#define LP5521_REG_RESET               0x0d
+#define LP5521_REG_GPO                 0x0e
+#define LP5521_REG_R_PROG_MEM          0x10
+#define LP5521_REG_G_PROG_MEM          0x30
+#define LP5521_REG_B_PROG_MEM          0x50
+
+#define LP5521_MODE_LOAD               "load"
+#define LP5521_MODE_RUN                        "run"
+#define LP5521_MODE_DIRECT_CONTROL     "direct"
+
+#define LP5521_CURRENT_1m5             0x0f
+#define LP5521_CURRENT_3m1             0x1f
+#define LP5521_CURRENT_4m7             0x2f
+#define LP5521_CURRENT_6m3             0x3f
+#define LP5521_CURRENT_7m9             0x4f
+#define LP5521_CURRENT_9m5             0x5f
+#define LP5521_CURRENT_11m1            0x6f
+#define LP5521_CURRENT_12m7            0x7f
+#define LP5521_CURRENT_14m3            0x8f
+#define LP5521_CURRENT_15m9            0x9f
+#define LP5521_CURRENT_17m5            0xaf
+#define LP5521_CURRENT_19m1            0xbf
+#define LP5521_CURRENT_20m7            0xcf
+#define LP5521_CURRENT_22m3            0xdf
+#define LP5521_CURRENT_23m9            0xef
+#define LP5521_CURRENT_25m5            0xff
+
+#define LP5521_PROGRAM_LENGTH          32      /* in bytes */
+
+struct lp5521_chip {
+       struct mutex            lock;
+       struct i2c_client       *client;
+       char                    *mode;
+       int                     red;
+       int                     green;
+       int                     blue;
+};
+
+static int lp5521_set_mode(struct lp5521_chip *chip, char *mode);
+
+static int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+       s32 ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               return -EIO;
+
+       *buf = ret;
+       return 0;
+}
+
+static int lp5521_configure(struct i2c_client *client)
+{
+       int ret = 0;
+
+       /* Enable chip and set light to logarithmic mode*/
+       ret |= lp5521_write(client, LP5521_REG_ENABLE, 0xc0);
+
+       /* setting all color pwms to direct control mode */
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3f);
+
+       /* setting current to 4.7 mA for all channels */
+       ret |= lp5521_write(client, LP5521_REG_R_CNTRL, LP5521_CURRENT_4m7);
+       ret |= lp5521_write(client, LP5521_REG_G_CNTRL, LP5521_CURRENT_4m7);
+       ret |= lp5521_write(client, LP5521_REG_B_CNTRL, LP5521_CURRENT_4m7);
+
+       /* Enable auto-powersave, set charge pump to auto, red to battery */
+       ret |= lp5521_write(client, LP5521_REG_MISC, 0x3c);
+
+       /* initialize all channels pwm to zero */
+       ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+       /* Not much can be done about errors at this point */
+       return ret;
+}
+
+static int lp5521_load_program(struct lp5521_chip *chip, u8 *pattern)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       /* Enter load program mode for all led channels */
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15); /* 0001 0101 */
+       if (ret)
+               return ret;
+
+       if (chip->red)
+               ret |= i2c_smbus_write_i2c_block_data(client,
+                                                     LP5521_REG_R_PROG_MEM,
+                                                     LP5521_PROGRAM_LENGTH,
+                                                     pattern);
+       if (chip->green)
+               ret |= i2c_smbus_write_i2c_block_data(client,
+                                                     LP5521_REG_G_PROG_MEM,
+                                                     LP5521_PROGRAM_LENGTH,
+                                                     pattern);
+       if (chip->blue)
+               ret |= i2c_smbus_write_i2c_block_data(client,
+                                                     LP5521_REG_B_PROG_MEM,
+                                                     LP5521_PROGRAM_LENGTH,
+                                                     pattern);
+
+       return ret;
+}
+
+static int lp5521_run_program(struct lp5521_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 mask = 0xc0;
+       u8 exec_state = 0;
+       u8 enable_reg;
+
+       ret = lp5521_read(client, LP5521_REG_ENABLE, &enable_reg);
+       if (ret)
+               goto fail;
+
+       enable_reg &= mask;
+
+       /* set all active channels exec state to countinous run*/
+       exec_state |= (chip->red   << 5);
+       exec_state |= (chip->green << 3);
+       exec_state |= (chip->blue  << 1);
+
+       enable_reg |= exec_state;
+
+       ret |= lp5521_write(client, LP5521_REG_ENABLE, enable_reg);
+
+       /* set op-mode to run for active channels, disabled for others */
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, exec_state);
+
+fail:
+       return ret;
+}
+
+/*--------------------------------------------------------------*/
+/*                     Sysfs interface                         */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_active_channels(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+       char channels[4];
+       int pos = 0;
+
+#ifdef LED_CONNECTED_WRONG
+       if (chip->blue)
+               pos += sprintf(channels + pos, "r");
+       if (chip->green)
+               pos += sprintf(channels + pos, "g");
+       if (chip->red)
+               pos += sprintf(channels + pos, "b");
+
+#else
+       if (chip->red)
+               pos += sprintf(channels + pos, "r");
+       if (chip->green)
+               pos += sprintf(channels + pos, "g");
+       if (chip->blue)
+               pos += sprintf(channels + pos, "b");
+#endif
+
+       channels[pos] = '\0';
+
+       return sprintf(buf, "%s\n", channels);
+}
+
+static ssize_t store_active_channels(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+       chip->red = 0;
+       chip->green = 0;
+       chip->blue = 0;
+
+#ifdef LED_CONNECTED_WRONG
+       if (strchr(buf, 'r') != NULL)
+               chip->blue = 1;
+       if (strchr(buf, 'b') != NULL)
+               chip->red = 1;
+#else
+       if (strchr(buf, 'r') != NULL)
+               chip->red = 1;
+       if (strchr(buf, 'b') != NULL)
+               chip->blue = 1;
+#endif
+       if (strchr(buf, 'g') != NULL)
+               chip->green = 1;
+
+       return len;
+}
+
+static ssize_t show_color(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret = 0;
+       u8 r, g, b;
+
+       ret |= lp5521_read(client, LP5521_REG_R_PWM, &r);
+       ret |= lp5521_read(client, LP5521_REG_G_PWM, &g);
+       ret |= lp5521_read(client, LP5521_REG_B_PWM, &b);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%.2x:%.2x:%.2x\n", r, g, b);
+}
+
+static ssize_t store_color(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int ret;
+       unsigned r, g, b;
+
+
+       ret = sscanf(buf, "%2x:%2x:%2x", &r, &g, &b);
+       if (ret != 3)
+               return  -EINVAL;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5521_write(client, LP5521_REG_R_PWM, (u8)r);
+       ret = lp5521_write(client, LP5521_REG_G_PWM, (u8)g);
+       ret = lp5521_write(client, LP5521_REG_B_PWM, (u8)b);
+
+       mutex_unlock(&chip->lock);
+
+       return len;
+}
+
+static ssize_t store_load(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+       int  ret, nrchars, offset = 0, i = 0;
+       char c[3];
+       unsigned cmd;
+       u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+
+       while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto fail;
+               pattern[i] = (u8)cmd;
+
+               offset += nrchars;
+               i++;
+       }
+
+       /* pattern commands are always two bytes long */
+       if (i % 2)
+               goto fail;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5521_load_program(chip, pattern);
+       mutex_unlock(&chip->lock);
+
+       if (ret) {
+               dev_err(dev, "lp5521 failed loading pattern\n");
+               return ret;
+       }
+
+       return len;
+fail:
+       dev_err(dev, "lp5521 wrong pattern format\n");
+       return -EINVAL;
+}
+
+static ssize_t show_mode(struct device *dev,
+                        struct device_attribute *attr,
+                        char *buf)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", chip->mode);
+}
+
+static ssize_t store_mode(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+
+       mutex_lock(&chip->lock);
+
+       if (!strncmp(buf, "run", 3))
+               lp5521_set_mode(chip, LP5521_MODE_RUN);
+       else if (!strncmp(buf, "load", 4))
+               lp5521_set_mode(chip, LP5521_MODE_LOAD);
+       else if (!strncmp(buf, "direct", 6))
+               lp5521_set_mode(chip, LP5521_MODE_DIRECT_CONTROL);
+
+       mutex_unlock(&chip->lock);
+
+       return len;
+}
+
+static ssize_t show_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int ret = 0;
+       u8 r_curr, g_curr, b_curr;
+
+       ret |= lp5521_read(client, LP5521_REG_R_CNTRL, &r_curr);
+       ret |= lp5521_read(client, LP5521_REG_G_CNTRL, &g_curr);
+       ret |= lp5521_read(client, LP5521_REG_B_CNTRL, &b_curr);
+
+       if (ret)
+               return ret;
+
+       r_curr = r_curr >> 4;
+       g_curr = g_curr >> 4;
+       b_curr = b_curr >> 4;
+
+       if (r_curr == g_curr && g_curr == b_curr)
+               return sprintf(buf, "%x\n", r_curr);
+       else
+               return sprintf(buf, "%x %x %x\n", r_curr, g_curr, b_curr);
+}
+
+static ssize_t store_current(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = dev_get_drvdata(dev);
+       struct i2c_client *client = chip->client;
+       int ret;
+       unsigned curr;
+
+       ret = sscanf(buf, "%1x", &curr);
+       if (ret != 1)
+               return  -EINVAL;
+
+       /* current level is determined by the 4 upper bits, rest is ones */
+       curr = (curr << 4) | 0x0f;
+
+       mutex_lock(&chip->lock);
+
+       ret |= lp5521_write(client, LP5521_REG_R_CNTRL, (u8)curr);
+       ret |= lp5521_write(client, LP5521_REG_G_CNTRL, (u8)curr);
+       ret |= lp5521_write(client, LP5521_REG_B_CNTRL, (u8)curr);
+
+       mutex_unlock(&chip->lock);
+
+       return len;
+}
+
+static DEVICE_ATTR(color, S_IRUGO | S_IWUGO, show_color, store_color);
+static DEVICE_ATTR(load, S_IWUGO, NULL, store_load);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUGO, show_mode, store_mode);
+static DEVICE_ATTR(active_channels, S_IRUGO | S_IWUGO,
+                  show_active_channels, store_active_channels);
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       int ret;
+
+       ret = device_create_file(dev, &dev_attr_color);
+       if (ret)
+               goto fail1;
+       ret = device_create_file(dev, &dev_attr_load);
+       if (ret)
+               goto fail2;
+       ret = device_create_file(dev, &dev_attr_active_channels);
+       if (ret)
+               goto fail3;
+       ret = device_create_file(dev, &dev_attr_mode);
+       if (ret)
+               goto fail4;
+       ret = device_create_file(dev, &dev_attr_led_current);
+       if (ret)
+               goto fail5;
+       return 0;
+
+fail5:
+       device_remove_file(dev, &dev_attr_mode);
+fail4:
+       device_remove_file(dev, &dev_attr_active_channels);
+fail3:
+       device_remove_file(dev, &dev_attr_load);
+fail2:
+       device_remove_file(dev, &dev_attr_color);
+fail1:
+       return ret;
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+
+       device_remove_file(dev, &dev_attr_led_current);
+       device_remove_file(dev, &dev_attr_mode);
+       device_remove_file(dev, &dev_attr_active_channels);
+       device_remove_file(dev, &dev_attr_color);
+
+       if (!strcmp(chip->mode, LP5521_MODE_LOAD))
+               device_remove_file(dev, &dev_attr_load);
+}
+
+/*--------------------------------------------------------------*/
+/*                     Set chip operating mode                 */
+/*--------------------------------------------------------------*/
+
+static int lp5521_set_mode(struct lp5521_chip *chip, char *mode)
+{
+       struct i2c_client *client = chip->client ;
+       int ret = 0;
+
+       /* if in that mode already do nothing, except for run */
+       if (!strcmp(mode, chip->mode) && strcmp(mode, LP5521_MODE_RUN))
+               return 0;
+
+       if (!strcmp(mode, LP5521_MODE_RUN))
+               ret = lp5521_run_program(chip);
+
+       if (!strcmp(mode, LP5521_MODE_LOAD))
+               ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x15);
+
+       if (!strcmp(mode, LP5521_MODE_DIRECT_CONTROL))
+               ret |= lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+
+       chip->mode = mode;
+
+       return ret;
+}
+
+/*--------------------------------------------------------------*/
+/*                     Probe, Attach, Remove                   */
+/*--------------------------------------------------------------*/
+static struct i2c_driver lp5521_driver;
+
+static int lp5521_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct lp5521_chip *chip;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->client    = client;
+       strncpy(client->name, LP5521_DRIVER_NAME, I2C_NAME_SIZE);
+       i2c_set_clientdata(client, chip);
+
+       mutex_init(&chip->lock);
+
+       ret = lp5521_configure(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "lp5521 error configuring chip \n");
+               goto fail1;
+       }
+
+       /* Set default values */
+       chip->mode      = LP5521_MODE_DIRECT_CONTROL;
+       chip->red       = 1;
+       chip->green     = 1;
+       chip->blue      = 1;
+
+       ret = lp5521_register_sysfs(client);
+       if (ret)
+               dev_err(&client->dev, "lp5521 registering sysfs failed \n");
+
+       return ret;
+
+fail1:
+       kfree(chip);
+       return ret;
+}
+
+static int lp5521_remove(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+
+       lp5521_unregister_sysfs(client);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp5521_id[] = {
+       { LP5521_DRIVER_NAME, 0},
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+       .driver = {
+               .name   = LP5521_DRIVER_NAME,
+       },
+       .probe          = lp5521_probe,
+       .remove         = __devexit_p(lp5521_remove),
+       .id_table       = lp5521_id,
+};
+
+static int __init lp5521_init(void)
+{
+       return i2c_add_driver(&lp5521_driver);
+}
+
+static void __exit lp5521_exit(void)
+{
+       i2c_del_driver(&lp5521_driver);
+}
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_DESCRIPTION("lp5521 LED driver");
+MODULE_LICENSE("GPL");
+
+module_init(lp5521_init);
+module_exit(lp5521_exit);
index 176126d3a01d3054318347cff48dfce8dc2805a1..3e6e2ade92c2041039f16fa49a0332106288cf91 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2004 Texas Instruments, Inc.
  *
 #include <linux/delay.h>
 #include <linux/rtc.h>
 #include <linux/bcd.h>
+#include <linux/i2c/menelaus.h>
 
+#include <asm/mach-types.h>
 #include <asm/mach/irq.h>
 
 #include <mach/gpio.h>
-#include <mach/menelaus.h>
 
 #define DRIVER_NAME                    "menelaus"
 
-#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);
 
@@ -152,7 +76,7 @@ static int menelaus_write_reg(int reg, u8 value)
        int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
 
        if (val < 0) {
-               pr_err(DRIVER_NAME ": write error");
+               dev_err(&the_menelaus->client->dev, "write error");
                return val;
        }
 
@@ -164,7 +88,7 @@ static int menelaus_read_reg(int reg)
        int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
 
        if (val < 0)
-               pr_err(DRIVER_NAME ": read error");
+               dev_err(&the_menelaus->client->dev, "read error");
 
        return val;
 }
@@ -248,10 +172,10 @@ static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw)
                return;
 
        if (!(reg & 0x1))
-               card_mask |= (1 << 0);
+               card_mask |= MCT_PIN_ST_S1_CD_ST;
 
        if (!(reg & 0x2))
-               card_mask |= (1 << 1);
+               card_mask |= MCT_PIN_ST_S2_CD_ST;
 
        if (menelaus_hw->mmc_callback)
                menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
@@ -276,14 +200,14 @@ int menelaus_set_mmc_opendrain(int slot, int enable)
        val = ret;
        if (slot == 1) {
                if (enable)
-                       val |= 1 << 2;
+                       val |= MCT_CTRL1_S1_CMD_OD;
                else
-                       val &= ~(1 << 2);
+                       val &= ~MCT_CTRL1_S1_CMD_OD;
        } else {
                if (enable)
-                       val |= 1 << 3;
+                       val |= MCT_CTRL1_S2_CMD_OD;
                else
-                       val &= ~(1 << 3);
+                       val &= ~MCT_CTRL1_S2_CMD_OD;
        }
        ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
        mutex_unlock(&the_menelaus->lock);
@@ -300,11 +224,11 @@ int menelaus_set_slot_sel(int enable)
        ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
        if (ret < 0)
                goto out;
-       ret |= 0x02;
+       ret |= GPIO2_DIR_INPUT;
        if (enable)
-               ret |= 1 << 5;
+               ret |= GPIO_CTRL_SLOTSELEN;
        else
-               ret &= ~(1 << 5);
+               ret &= ~GPIO_CTRL_SLOTSELEN;
        ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
 out:
        mutex_unlock(&the_menelaus->lock);
@@ -312,6 +236,34 @@ out:
 }
 EXPORT_SYMBOL(menelaus_set_slot_sel);
 
+int menelaus_enable_slot(int slot, int enable)
+{
+       int ret, val;
+
+       mutex_lock(&the_menelaus->lock);
+       ret = menelaus_read_reg(MENELAUS_MCT_CTRL3);
+       if (ret < 0)
+               goto out;
+       val = ret;
+       if (slot == 1) {
+               if (enable)
+                       val |= MCT_CTRL3_SLOT1_EN;
+               else
+                       val &= ~MCT_CTRL3_SLOT1_EN;
+       } else {
+               if (enable)
+                       val |= MCT_CTRL3_SLOT2_EN;
+               else
+                       val &= MCT_CTRL3_SLOT2_EN;
+       }
+       ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
+
+out:
+       mutex_unlock(&the_menelaus->lock);
+       return ret;
+}
+EXPORT_SYMBOL(menelaus_enable_slot);
+
 int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
 {
        int ret, val;
@@ -329,14 +281,14 @@ int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
        val = ret;
        if (slot == 1) {
                if (cd_en)
-                       val |= (1 << 4) | (1 << 6);
+                       val |= MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN;
                else
-                       val &= ~((1 << 4) | (1 << 6));
+                       val &= ~(MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN);
        } else {
                if (cd_en)
-                       val |= (1 << 5) | (1 << 7);
+                       val |= MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN;
                else
-                       val &= ~((1 << 5) | (1 << 7));
+                       val &= ~(MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN);
        }
        ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
        if (ret < 0)
@@ -348,25 +300,25 @@ int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
        val = ret;
        if (slot == 1) {
                if (enable)
-                       val |= 1 << 0;
+                       val |= MCT_CTRL3_SLOT1_EN;
                else
-                       val &= ~(1 << 0);
+                       val &= ~MCT_CTRL3_SLOT1_EN;
        } else {
                int b;
 
                if (enable)
-                       ret |= 1 << 1;
+                       val |= MCT_CTRL3_SLOT2_EN;
                else
-                       ret &= ~(1 << 1);
+                       val &= ~MCT_CTRL3_SLOT2_EN;
                b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
-               b &= ~0x03;
+               b &= ~(MCT_CTRL2_VS2_SEL_D0 | MCT_CTRL2_VS2_SEL_D1);
                b |= power;
                ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
                if (ret < 0)
                        goto out;
        }
        /* Disable autonomous shutdown */
-       val &= ~(0x03 << 2);
+       val &= ~(MCT_CTRL3_S1_AUTO_EN | MCT_CTRL3_S2_AUTO_EN);
        ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
 out:
        mutex_unlock(&the_menelaus->lock);
@@ -551,7 +503,7 @@ int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
        if (!the_menelaus->vcore_hw_mode) {
                val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
                /* HW mode, turn OFF byte comparator */
-               val |= ((1 << 7) | (1 << 5));
+               val |= (VCORE_CTRL1_HW_NSW | VCORE_CTRL1_BYP_COMP);
                ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
                the_menelaus->vcore_hw_mode = 1;
        }
@@ -748,7 +700,7 @@ int menelaus_set_regulator_sleep(int enable, u32 val)
        ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
        if (ret < 0)
                goto out;
-       t = ((1 << 6) | 0x04);
+       t = (GPIO_CTRL_SLPCTLEN | GPIO3_DIR_INPUT);
        if (enable)
                ret |= t;
        else
@@ -929,7 +881,7 @@ static int menelaus_set_time(struct device *dev, struct rtc_time *t)
                return status;
        status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
        if (status < 0) {
-               dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
+               dev_err(&the_menelaus->client->dev, "rtc write reg %02x"
                                "err %d\n", MENELAUS_RTC_WKDAY, status);
                return status;
        }
@@ -1175,7 +1127,7 @@ static int menelaus_probe(struct i2c_client *client,
        /* If a true probe check the device */
        rev = menelaus_read_reg(MENELAUS_REV);
        if (rev < 0) {
-               pr_err(DRIVER_NAME ": device not found");
+               dev_err(&client->dev, "device not found");
                err = -ENODEV;
                goto fail1;
        }
@@ -1195,7 +1147,7 @@ static int menelaus_probe(struct i2c_client *client,
                err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED,
                                  DRIVER_NAME, menelaus);
                if (err) {
-                       dev_dbg(&client->dev,  "can't get IRQ %d, err %d\n",
+                       dev_dbg(&client->dev,  "can't get IRQ %d, err %d",
                                        client->irq, err);
                        goto fail1;
                }
@@ -1204,7 +1156,7 @@ static int menelaus_probe(struct i2c_client *client,
        mutex_init(&menelaus->lock);
        INIT_WORK(&menelaus->work, menelaus_work);
 
-       pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+       dev_info(&client->dev, "Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
 
        val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
        if (val < 0)
@@ -1259,15 +1211,7 @@ static struct i2c_driver menelaus_i2c_driver = {
 
 static int __init menelaus_init(void)
 {
-       int res;
-
-       res = i2c_add_driver(&menelaus_i2c_driver);
-       if (res < 0) {
-               pr_err(DRIVER_NAME ": driver registration failed\n");
-               return res;
-       }
-
-       return 0;
+       return i2c_add_driver(&menelaus_i2c_driver);
 }
 
 static void __exit menelaus_exit(void)
diff --git a/drivers/i2c/chips/tlv320aic23.c b/drivers/i2c/chips/tlv320aic23.c
new file mode 100644 (file)
index 0000000..10671e8
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ *   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 <mach/aic23.h>
+#include <mach/mcbsp.h>
+
+#define TLV320AIC23_VERSION    "1.8"
+#define TLV320AIC23_DATE       "10-Feb-2006"
+#define MAX_VOL                        100
+#define MIN_VOL                        0
+#define MAX_GAIN               100
+#define MIN_GAIN               0
+#define OUTPUT_VOLUME_MIN       LHV_MIN
+#define OUTPUT_VOLUME_MAX       LHV_MAX
+#define OUTPUT_VOLUME_RANGE     (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MIN       LIV_MIN
+#define INPUT_VOLUME_MAX       LIV_MAX
+#define INPUT_VOLUME_RANGE     (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+/* I2C Addresses to scan */
+static unsigned short normal_i2c[] = { TLV320AIC23ID1, TLV320AIC23ID2, \
+                                      I2C_CLIENT_END };
+/*static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };*/
+
+/* This makes all addr_data:s */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver aic23_driver;
+static struct i2c_client *new_client;
+static int selftest;
+static struct platform_device audio_i2c_device;
+
+static struct aic23_info {
+       u16 volume_reg_left;
+       u16 volume_reg_right;
+       u16 input_gain_reg_left;
+       u16 input_gain_reg_right;
+       u16 power;                      /* For POWER_DOWN_CONTROL_ADDR */
+       u16 mask;                       /* For ANALOG_AUDIO_CONTROL_ADDR */
+       int mic_loopback;
+       int mic_enable;
+       int sta;
+       int power_down;
+       int initialized;
+} aic23_info_l;
+
+static int _aic23_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+       u8 val, wreg;
+
+       /* TLV320AIC23 has 7 bit address and 9 bits of data
+        * so we need to switch one data bit into reg and rest
+        * of data into val
+        */
+
+       wreg = (reg << 1);
+       val = (0x01 & (value >> 8));
+       wreg = (wreg | val);
+       val = (0x00ff & value);
+
+       return i2c_smbus_write_byte_data(client, wreg, val);
+}
+
+int aic23_write_value(u8 reg, u16 value)
+{
+       static struct i2c_client *client;
+       client = new_client;
+       _aic23_write_value(client, reg, value);
+
+       return 0;
+}
+
+/*
+ * Configures the McBSP3 which is used to send clock to the AIC23 codec.
+ * The input clock rate from DSP is 12MHz.
+ * The DSP clock must be on before this is called.
+ */
+static int omap_mcbsp3_aic23_clock_init(void)
+{
+       u16 w;
+
+       /* enable 12MHz clock to mcbsp 1 & 3 */
+       __raw_writew(__raw_readw(DSP_IDLECT2) | (1<<1), DSP_IDLECT2);
+       __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1<<1, DSP_RSTCT2);
+
+       /* disable sample rate generator */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR1, 0x0000);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, 0x0000);
+
+       /* pin control register */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, PCR0,(CLKXM | CLKXP | CLKRP));
+
+       /* configure srg to send 12MHz pulse from dsp peripheral clock */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR1, 0x0000);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR2, CLKSM);
+
+       /* enable sample rate generator */
+       w = OMAP_MCBSP_READ(OMAP1610_MCBSP3_BASE, SPCR2);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, (w | FREE | GRST));
+       printk("Clock enabled to MCBSP1 & 3 \n");
+
+       return 0;
+}
+
+static int aic23_detect_client(struct i2c_adapter *adapter, int address,
+                                    int kind)
+{
+       int err = 0;
+       const char *client_name = "TLV320AIC23 Audio Codec";
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
+                                    I2C_FUNC_SMBUS_WRITE_BYTE)) {
+               printk(KERN_WARNING "%s functionality check failed\n",
+                      client_name);
+               return err;
+       }
+
+       if (!(new_client = kmalloc(sizeof(struct i2c_client),
+                                  GFP_KERNEL))) {
+               err = -ENOMEM;
+               printk(KERN_WARNING "Couldn't allocate memory for %s\n",
+                      client_name);
+               return err;
+       }
+
+       memset(new_client, 0x00, sizeof(struct i2c_client));
+       new_client->addr = address;
+       new_client->adapter = adapter;
+       new_client->driver = &aic23_driver;
+       new_client->flags = 0;
+       strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+
+       if ((err = i2c_attach_client(new_client))) {
+               printk(KERN_WARNING "Couldn't attach %s\n", client_name);
+               kfree(new_client);
+               return err;
+       }
+
+       if (platform_device_register(&audio_i2c_device)) {
+               printk(KERN_WARNING "Failed to register audio i2c device\n");
+               selftest = -ENODEV;
+               return selftest;
+       }
+       /* FIXME: Do in board-specific file */
+       omap_mcbsp3_aic23_clock_init();
+
+       if (!aic23_info_l.power_down)
+               aic23_power_up();
+       aic23_info_l.initialized = 1;
+
+       return 0;
+}
+
+static int aic23_detach_client(struct i2c_client *client)
+{
+       int err;
+
+       platform_device_unregister(&audio_i2c_device);
+
+       if ((err = i2c_detach_client(client))) {
+               printk("aic23.o: Client deregistration failed, \
+                      client not detached.\n");
+               return err;
+       }
+       kfree(client);
+       return 0;
+}
+
+static int aic23_attach_adapter(struct i2c_adapter *adapter)
+{
+       int res;
+
+       res = i2c_probe(adapter, &addr_data, &aic23_detect_client);
+       return res;
+}
+
+static struct i2c_driver aic23_driver = {
+       .driver = {
+               .name   = "OMAP+TLV320AIC23 codec",
+               /*.flags        = I2C_DF_NOTIFY,*/
+       },
+       .id             = I2C_DRIVERID_MISC, /* Experimental ID */
+       .attach_adapter = aic23_attach_adapter,
+       .detach_client  = aic23_detach_client,
+};
+
+static void update_volume_left(int volume)
+{
+       u16 val = 0;
+       val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, val);
+       aic23_info_l.volume_reg_left = volume;
+}
+
+static void update_volume_right(int volume)
+{
+       u16 val = 0;
+       val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, val);
+       aic23_info_l.volume_reg_right = volume;
+}
+
+static void set_mic(int mic_en)
+{
+       u16 dg_ctrl;
+
+       if (mic_en) {
+               aic23_info_l.power = OSC_OFF | LINE_OFF;
+               dg_ctrl = ADCHP_ON;
+               aic23_info_l.mask &= ~MICM_MUTED;
+               aic23_info_l.mask |= MICB_20DB; /* STE_ENABLED */
+       } else {
+               aic23_info_l.power =
+                       OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+               dg_ctrl = 0x00;
+               aic23_info_l.mask =
+                       DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+       }
+       aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+                               aic23_info_l.power);
+       aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, dg_ctrl);
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_info_l.mic_enable = mic_en;
+
+       printk(KERN_INFO "aic23 mic state: %i\n", mic_en);
+}
+
+static void aic23_init_power(void)
+{
+       aic23_write_value(RESET_CONTROL_ADDR, 0x00);
+
+       if (aic23_info_l.initialized == 0) {
+               aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+               aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       }
+       else {
+               update_volume_left(aic23_info_l.volume_reg_left);
+               update_volume_right(aic23_info_l.volume_reg_right);
+       }
+
+       aic23_info_l.mask = DAC_SELECTED | INSEL_MIC | MICM_MUTED;
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, 0x00);
+       aic23_write_value(DIGITAL_AUDIO_FORMAT_ADDR, LRP_ON | FOR_DSP);
+       aic23_write_value(SAMPLE_RATE_CONTROL_ADDR, USB_CLK_ON);
+       aic23_write_value(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+       aic23_info_l.power = OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
+       aic23_write_value(POWER_DOWN_CONTROL_ADDR,
+                               aic23_info_l.power);
+
+       /* enable mic input */
+       if (aic23_info_l.mic_enable)
+               set_mic(aic23_info_l.mic_enable);
+
+       printk(KERN_INFO "aic23_init_power() done\n");
+}
+
+void aic23_power_down(void)
+{
+       if (aic23_info_l.initialized) {
+               printk("aic23 powering down\n");
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, 0xff);
+       }
+       aic23_info_l.power_down = 1;
+}
+
+void aic23_power_up(void)
+{
+       if (aic23_info_l.initialized) {
+               printk("aic23 powering up\n");
+               aic23_init_power();
+       }
+       aic23_info_l.power_down = 0;
+}
+
+/*----------------------------------------------------------------------*/
+/*                     sysfs initializations                           */
+/*----------------------------------------------------------------------*/
+
+static ssize_t store_volume_left(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       signed volume;
+
+       sscanf(buf, "%i", &volume);
+
+       if (volume < MIN_VOL) {
+               aic23_power_down();
+               return count;
+       } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+               aic23_info_l.volume_reg_left = volume;
+               aic23_power_up();
+               return count;
+       }
+       if (volume > MAX_VOL)
+               volume = MAX_VOL;
+
+       update_volume_left(volume);
+       return count;
+}
+
+static ssize_t show_volume_left(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.volume_reg_left);
+}
+
+static DEVICE_ATTR(volume_left, S_IRUGO | S_IWUGO,
+                  show_volume_left, store_volume_left);
+
+static ssize_t store_volume_right(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       signed volume;
+
+       sscanf(buf, "%i", &volume);
+       if (volume < MIN_VOL) {
+               aic23_power_down();
+               return count;
+       } else if (volume > MIN_VOL && aic23_info_l.power_down) {
+               aic23_info_l.volume_reg_right = volume;
+               aic23_power_up();
+               return count;
+       }
+       if (volume > MAX_VOL)
+               volume = MAX_VOL;
+
+       update_volume_right(volume);
+       return count;
+}
+
+static ssize_t show_volume_right(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.volume_reg_right);
+}
+
+static DEVICE_ATTR(volume_right, S_IRUGO | S_IWUGO,
+                  show_volume_right, store_volume_right);
+
+static ssize_t store_gain_left(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t count)
+{
+       u16 val = 0;
+       unsigned gain;
+
+       sscanf(buf, "%u", &gain);
+       if (gain > MAX_VOL)
+               gain = MAX_VOL;
+
+       val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+       aic23_write_value(LEFT_LINE_VOLUME_ADDR, val);
+       aic23_info_l.input_gain_reg_left = gain;
+
+       return count;
+}
+
+static ssize_t show_gain_left(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_left);
+}
+
+static DEVICE_ATTR(gain_left, S_IRUGO | S_IWUSR, show_gain_left,
+                  store_gain_left);
+
+static ssize_t store_gain_right(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u16 val = 0;
+       unsigned gain;
+
+       sscanf(buf, "%u", &gain);
+       if (gain > MAX_VOL)
+               gain = MAX_VOL;
+
+       val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+       aic23_write_value(RIGHT_LINE_VOLUME_ADDR, val);
+       aic23_info_l.input_gain_reg_right = gain;
+
+       return count;
+}
+
+static ssize_t show_gain_right(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_right);
+}
+
+static DEVICE_ATTR(gain_right, S_IRUGO | S_IWUSR, show_gain_right,
+                  store_gain_right);
+
+static ssize_t store_mic_loopback(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       int mic;
+
+       sscanf(buf, "%i", &mic);
+       if (mic > 0) {
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+                                       OSC_OFF | ADC_OFF | LINE_OFF);
+               aic23_info_l.mask = STE_ENABLED | DAC_SELECTED \
+                                         | INSEL_MIC | MICB_20DB;
+               aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                                       aic23_info_l.mask);
+               mic = 1;
+       }
+       else {
+               aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
+                                       OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF);
+               mic = 0;
+       }
+       aic23_info_l.mic_loopback = mic;
+
+       return count;
+}
+
+static ssize_t show_mic_loopback(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.mic_loopback);
+}
+
+static DEVICE_ATTR(mic_loopback, S_IRUGO | S_IWUSR,
+                  show_mic_loopback, store_mic_loopback);
+
+static ssize_t store_st_attenuation(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       unsigned sta;
+       u16 tmp;
+
+       sscanf(buf, "%u", &sta);
+       if (sta > 3)
+               sta = 3;
+
+       tmp = aic23_info_l.mask;
+       tmp &= 0x3f;
+
+       aic23_info_l.mask =  tmp | STA_REG(sta);
+       aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
+                               aic23_info_l.mask);
+       aic23_info_l.sta = sta;
+
+       return count;
+}
+
+static ssize_t show_st_attenuation(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.sta);
+}
+
+static DEVICE_ATTR(st_attenuation, S_IRUGO | S_IWUSR,
+                  show_st_attenuation, store_st_attenuation);
+
+static ssize_t store_mic_enable(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       int mic;
+
+       sscanf(buf, "%i", &mic);
+       set_mic(mic);
+
+       return count;
+}
+
+static ssize_t show_mic_enable(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", aic23_info_l.mic_enable);
+}
+
+static DEVICE_ATTR(mic_enable, S_IRUGO | S_IWUSR,
+       show_mic_enable, store_mic_enable);
+
+static ssize_t show_audio_selftest(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%i\n", selftest);
+}
+
+static DEVICE_ATTR(audio_selftest, S_IRUGO | S_IWUSR,
+               show_audio_selftest, NULL);
+
+static int audio_i2c_probe(struct platform_device *dev)
+{
+       int r;
+
+       if ((r = device_create_file(&dev->dev, &dev_attr_volume_left)) != 0)
+               return r;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_volume_right)) != 0)
+               goto err_volume_left;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_gain_right)) != 0)
+               goto err_volume_right;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_gain_left)) != 0)
+               goto err_gain_right;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_mic_loopback)) != 0)
+               goto err_gain_left;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_mic_enable)) != 0)
+               goto err_mic_loopback;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_st_attenuation)) != 0)
+               goto err_mic_enable;
+       else if ((r = device_create_file(&dev->dev,
+               &dev_attr_audio_selftest)) != 0)
+               goto err_st_attenuation;
+       else
+               return r;
+
+err_st_attenuation:
+       device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+err_mic_enable:
+       device_remove_file(&dev->dev, &dev_attr_mic_enable);
+err_mic_loopback:
+       device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+err_gain_left:
+       device_remove_file(&dev->dev, &dev_attr_gain_left);
+err_gain_right:
+       device_remove_file(&dev->dev, &dev_attr_gain_right);
+err_volume_right:
+       device_remove_file(&dev->dev, &dev_attr_volume_right);
+err_volume_left:
+       device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+       return r;
+}
+
+static int audio_i2c_remove(struct platform_device *dev)
+{
+       device_remove_file(&dev->dev, &dev_attr_st_attenuation);
+       device_remove_file(&dev->dev, &dev_attr_mic_enable);
+       device_remove_file(&dev->dev, &dev_attr_mic_loopback);
+       device_remove_file(&dev->dev, &dev_attr_gain_left);
+       device_remove_file(&dev->dev, &dev_attr_gain_right);
+       device_remove_file(&dev->dev, &dev_attr_volume_right);
+       device_remove_file(&dev->dev, &dev_attr_volume_left);
+
+       return 0;
+}
+
+/*----------------------------------------------------------------*/
+/*                     PM functions                              */
+/*----------------------------------------------------------------*/
+
+static void audio_i2c_shutdown(struct platform_device *dev)
+{
+       /* Let's mute the codec before powering off to prevent
+       * glitch in the sound
+       */
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_power_down();
+}
+
+static int audio_i2c_suspend(struct platform_device *dev, pm_message_t state)
+{
+       /* Let's mute the codec before powering off to prevent
+        * glitch in the sound
+        */
+       aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
+       aic23_power_down();
+
+       return 0;
+}
+
+static int audio_i2c_resume(struct platform_device *dev)
+{
+       aic23_power_up();
+
+       return 0;
+}
+
+static struct platform_driver audio_i2c_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "audio-i2c",
+       },
+       .shutdown       = audio_i2c_shutdown,
+       .probe          = audio_i2c_probe,
+       .remove         = audio_i2c_remove,
+       .suspend        = audio_i2c_suspend,
+       .resume         = audio_i2c_resume,
+};
+
+static struct platform_device audio_i2c_device = {
+       .name           = "audio-i2c",
+       .id             = -1,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init aic23_init(void)
+{
+       selftest =  0;
+       aic23_info_l.initialized = 0;
+
+       if (i2c_add_driver(&aic23_driver)) {
+               printk("aic23 i2c: Driver registration failed, \
+                     module not inserted.\n");
+               selftest = -ENODEV;
+               return selftest;
+       }
+
+       if (platform_driver_register(&audio_i2c_driver)) {
+               printk(KERN_WARNING "Failed to register audio i2c driver\n");
+               selftest = -ENODEV;
+               return selftest;
+       }
+
+       printk("TLV320AIC23 I2C version %s (%s)\n",
+              TLV320AIC23_VERSION, TLV320AIC23_DATE);
+
+       return selftest;
+}
+
+static void __exit aic23_exit(void)
+{
+       aic23_power_down();
+       i2c_del_driver(&aic23_driver);
+
+       platform_driver_unregister(&audio_i2c_driver);
+}
+
+MODULE_AUTHOR("Kai Svahn <kai.svahn@nokia.com>");
+MODULE_DESCRIPTION("I2C interface for TLV320AIC23 codec.");
+MODULE_LICENSE("GPL");
+
+module_init(aic23_init)
+module_exit(aic23_exit)
+
+EXPORT_SYMBOL(aic23_write_value);
+EXPORT_SYMBOL(aic23_power_up);
+EXPORT_SYMBOL(aic23_power_down);
diff --git a/drivers/i2c/chips/tsl2563.c b/drivers/i2c/chips/tsl2563.c
new file mode 100644 (file)
index 0000000..e05b880
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ * drivers/i2c/chips/tsl2563.c
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
+ * Contact: Mathias Nyman <mathias.nyman@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <mach/board.h>
+
+#define DRIVER_NAME  "tsl2563"
+
+/* Use this many bits for fraction part. */
+#define ADC_FRAC_BITS          (14)
+
+/* Given number of 1/10000's in ADC_FRAC_BITS precision. */
+#define FRAC10K(f)             (((f) * (1L << (ADC_FRAC_BITS))) / (10000))
+
+/* Bits used for fraction in calibration coefficients.*/
+#define CALIB_FRAC_BITS                (10)
+/* 0.5 in CALIB_FRAC_BITS precision */
+#define CALIB_FRAC_HALF                (1 << (CALIB_FRAC_BITS - 1))
+/* Make a fraction from a number n that was multiplied with b. */
+#define CALIB_FRAC(n, b)       (((n) << CALIB_FRAC_BITS) / (b))
+/* Decimal 10^(digits in sysfs presentation) */
+#define CALIB_BASE_SYSFS       (1000)
+
+#define TSL2563_CMD            (0x80)
+#define TSL2563_CLEARINT       (0x40)
+
+#define TSL2563_REG_CTRL       (0x00)
+#define TSL2563_REG_TIMING     (0x01)
+#define TSL2563_REG_LOWLOW     (0x02) /* data0 low threshold, 2 bytes */
+#define TSL2563_REG_LOWHIGH    (0x03)
+#define TSL2563_REG_HIGHLOW    (0x04) /* data0 high threshold, 2 bytes */
+#define TSL2563_REG_HIGHHIGH   (0x05)
+#define TSL2563_REG_INT                (0x06)
+#define TSL2563_REG_ID         (0x0a)
+#define TSL2563_REG_DATA0LOW   (0x0c) /* broadband sensor value, 2 bytes */
+#define TSL2563_REG_DATA0HIGH  (0x0d)
+#define TSL2563_REG_DATA1LOW   (0x0e) /* infrared sensor value, 2 bytes */
+#define TSL2563_REG_DATA1HIGH  (0x0f)
+
+#define TSL2563_CMD_POWER_ON   (0x03)
+#define TSL2563_CMD_POWER_OFF  (0x00)
+#define TSL2563_CTRL_POWER_MASK        (0x03)
+
+#define TSL2563_TIMING_13MS    (0x00)
+#define TSL2563_TIMING_100MS   (0x01)
+#define TSL2563_TIMING_400MS   (0x02)
+#define TSL2563_TIMING_MASK    (0x03)
+#define TSL2563_TIMING_GAIN16  (0x10)
+#define TSL2563_TIMING_GAIN1   (0x00)
+
+#define TSL2563_INT_DISBLED    (0x00)
+#define TSL2563_INT_LEVEL      (0x10)
+#define TSL2563_INT_PERSIST(n) ((n) & 0x0F)
+
+struct tsl2563_gainlevel_coeff {
+       u8 gaintime;
+       u16 min;
+       u16 max;
+};
+
+static struct tsl2563_gainlevel_coeff tsl2563_gainlevel_table[] = {
+       {
+               .gaintime       = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN16,
+               .min            = 0,
+               .max            = 65534,
+       }, {
+               .gaintime       = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN1,
+               .min            = 2048,
+               .max            = 65534,
+       }, {
+               .gaintime       = TSL2563_TIMING_100MS | TSL2563_TIMING_GAIN1,
+               .min            = 4095,
+               .max            = 37177,
+       }, {
+               .gaintime       = TSL2563_TIMING_13MS | TSL2563_TIMING_GAIN1,
+               .min            = 3000,
+               .max            = 65535,
+       },
+};
+
+struct tsl2563_chip {
+       struct mutex            lock;
+       struct i2c_client       *client;
+       struct device           *hwmon_dev;
+
+       /* Remember state for suspend and resume functions */
+       pm_message_t            state;
+
+       struct tsl2563_gainlevel_coeff *gainlevel;
+
+       /* Thresholds are in lux */
+       u16                     low_thres;
+       u16                     high_thres;
+       u8                      intr;
+
+       /* Calibration coefficients */
+       u32                     calib0;
+       u32                     calib1;
+
+       /* Cache current values, to be returned while suspended */
+       u32                     data0;
+       u32                     data1;
+};
+
+static int tsl2563_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       int ret;
+       u8 buf[2];
+
+       buf[0] = TSL2563_CMD | reg;
+       buf[1] = value;
+
+       ret = i2c_master_send(client, buf, sizeof(buf));
+       return (ret == sizeof(buf)) ? 0 : ret;
+}
+
+static int tsl2563_read(struct i2c_client *client, u8 reg, void *buf, int len)
+{
+       int ret;
+       u8 cmd = TSL2563_CMD | reg;
+
+       ret = i2c_master_send(client, &cmd, sizeof(cmd));
+       if (ret != sizeof(cmd))
+               return ret;
+
+       return i2c_master_recv(client, buf, len);
+}
+
+static int tsl2563_set_power(struct tsl2563_chip *chip, int on)
+{
+       struct i2c_client *client = chip->client;
+       u8 cmd;
+
+       cmd = on ? TSL2563_CMD_POWER_ON : TSL2563_CMD_POWER_OFF;
+       return tsl2563_write(client, TSL2563_REG_CTRL, cmd);
+}
+
+/*
+ * Return value is 0 for off, 1 for on, or a negative error
+ * code if reading failed.
+ */
+static int tsl2563_get_power(struct tsl2563_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 val;
+
+       ret = tsl2563_read(client, TSL2563_REG_CTRL, &val, sizeof(val));
+       if (ret != sizeof(val))
+               return ret;
+
+       return (val & TSL2563_CTRL_POWER_MASK) == TSL2563_CMD_POWER_ON;
+}
+
+static int tsl2563_configure(struct tsl2563_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = tsl2563_write(client, TSL2563_REG_TIMING,
+                       chip->gainlevel->gaintime);
+       if (ret)
+               goto out;
+
+       ret = tsl2563_write(client, TSL2563_REG_INT, chip->intr);
+
+out:
+       return ret;
+}
+
+static int tsl2563_detect(struct tsl2563_chip *chip)
+{
+       int ret;
+
+       ret = tsl2563_set_power(chip, 1);
+       if (ret)
+               return ret;
+
+       ret = tsl2563_get_power(chip);
+       if (ret < 0)
+               return ret;
+
+       return ret ? 0 : -ENODEV;
+}
+
+static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = tsl2563_read(client, TSL2563_REG_ID, id, sizeof(*id));
+       if (ret != sizeof(*id))
+               return ret;
+
+       return 0;
+}
+
+/*
+ * "Normalized" ADC value is one obtained with 400ms of integration time and
+ * 16x gain. This function returns the number of bits of shift needed to
+ * convert between normalized values and HW values obtained using given
+ * timing and gain settings.
+ */
+static int adc_shiftbits(u8 timing)
+{
+       int shift = 0;
+
+       switch (timing & TSL2563_TIMING_MASK) {
+       case TSL2563_TIMING_13MS:
+               shift += 5;
+               break;
+       case TSL2563_TIMING_100MS:
+               shift += 2;
+               break;
+       case TSL2563_TIMING_400MS:
+               /* no-op */
+               break;
+       }
+
+       if (!(timing & TSL2563_TIMING_GAIN16))
+               shift += 4;
+
+       return shift;
+}
+
+/* Convert a HW ADC value to normalized scale. */
+static u32 normalize_adc(u16 adc, u8 timing)
+{
+       return adc << adc_shiftbits(timing);
+}
+
+static void tsl2563_wait_adc(struct tsl2563_chip *chip)
+{
+       unsigned int delay;
+
+       switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) {
+       case TSL2563_TIMING_13MS:
+               delay = 14;
+               break;
+       case TSL2563_TIMING_100MS:
+               delay = 101;
+               break;
+       default:
+               delay = 402;
+       }
+       /*
+        * TODO: Make sure that we wait at least required delay but why we
+        * have to extend it one tick more?
+        */
+       schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2);
+}
+
+static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc)
+{
+       struct i2c_client *client = chip->client;
+
+       if (adc > chip->gainlevel->max || adc < chip->gainlevel->min) {
+
+               (adc > chip->gainlevel->max) ?
+                       chip->gainlevel++ : chip->gainlevel--;
+
+               tsl2563_write(client, TSL2563_REG_TIMING,
+                             chip->gainlevel->gaintime);
+
+               tsl2563_wait_adc(chip);
+               tsl2563_wait_adc(chip);
+
+               return 1;
+       } else
+               return 0;
+}
+
+static int tsl2563_get_adc(struct tsl2563_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       u8 buf0[2], buf1[2];
+       u16 adc0, adc1;
+       int retry = 1;
+       int ret = 0;
+
+       if (chip->state.event != PM_EVENT_ON)
+               goto out;
+
+       while (retry) {
+               ret = tsl2563_read(client,
+                                  TSL2563_REG_DATA0LOW | TSL2563_CLEARINT,
+                                  buf0, sizeof(buf0));
+               if (ret != sizeof(buf0))
+                       goto out;
+
+               ret = tsl2563_read(client, TSL2563_REG_DATA1LOW,
+                                  buf1, sizeof(buf1));
+               if (ret != sizeof(buf1))
+                       goto out;
+
+               adc0 = (buf0[1] << 8) + buf0[0];
+               adc1 = (buf1[1] << 8) + buf1[0];
+
+               retry = tsl2563_adjust_gainlevel(chip, adc0);
+       }
+
+       chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime);
+       chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime);
+
+       ret = 0;
+out:
+       return ret;
+}
+
+static inline int calib_to_sysfs(u32 calib)
+{
+       return (int) (((calib * CALIB_BASE_SYSFS) +
+                      CALIB_FRAC_HALF) >> CALIB_FRAC_BITS);
+}
+
+static inline u32 calib_from_sysfs(int value)
+{
+       return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
+}
+
+/*
+ * Conversions between lux and ADC values.
+ *
+ * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are
+ * appropriate constants. Different constants are needed for different
+ * kinds of light, determined by the ratio adc1/adc0 (basically the ratio
+ * of the intensities in infrared and visible wavelengths). lux_table below
+ * lists the upper threshold of the adc1/adc0 ratio and the corresponding
+ * constants.
+ */
+
+struct tsl2563_lux_coeff {
+       unsigned long ch_ratio;
+       unsigned long ch0_coeff;
+       unsigned long ch1_coeff;
+};
+
+static const struct tsl2563_lux_coeff lux_table[] = {
+       {
+               .ch_ratio       = FRAC10K(1300),
+               .ch0_coeff      = FRAC10K(315),
+               .ch1_coeff      = FRAC10K(262),
+       }, {
+               .ch_ratio       = FRAC10K(2600),
+               .ch0_coeff      = FRAC10K(337),
+               .ch1_coeff      = FRAC10K(430),
+       }, {
+               .ch_ratio       = FRAC10K(3900),
+               .ch0_coeff      = FRAC10K(363),
+               .ch1_coeff      = FRAC10K(529),
+       }, {
+               .ch_ratio       = FRAC10K(5200),
+               .ch0_coeff      = FRAC10K(392),
+               .ch1_coeff      = FRAC10K(605),
+       }, {
+               .ch_ratio       = FRAC10K(6500),
+               .ch0_coeff      = FRAC10K(229),
+               .ch1_coeff      = FRAC10K(291),
+       }, {
+               .ch_ratio       = FRAC10K(8000),
+               .ch0_coeff      = FRAC10K(157),
+               .ch1_coeff      = FRAC10K(180),
+       }, {
+               .ch_ratio       = FRAC10K(13000),
+               .ch0_coeff      = FRAC10K(34),
+               .ch1_coeff      = FRAC10K(26),
+       }, {
+               .ch_ratio       = ULONG_MAX,
+               .ch0_coeff      = 0,
+               .ch1_coeff      = 0,
+       },
+};
+
+/*
+ * Convert normalized, scaled ADC values to lux.
+ */
+static unsigned int adc_to_lux(u32 adc0, u32 adc1)
+{
+       const struct tsl2563_lux_coeff *lp = lux_table;
+       unsigned long ratio, lux, ch0 = adc0, ch1 = adc1;
+
+       ratio = ch0 ? ((ch1 << ADC_FRAC_BITS) / ch0) : ULONG_MAX;
+
+       while (lp->ch_ratio < ratio)
+               lp++;
+
+       lux = ch0 * lp->ch0_coeff - ch1 * lp->ch1_coeff;
+
+       return (unsigned int) (lux >> ADC_FRAC_BITS);
+}
+
+/*--------------------------------------------------------------*/
+/*                      Sysfs interface                         */
+/*--------------------------------------------------------------*/
+
+static ssize_t tsl2563_adc0_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = tsl2563_get_adc(chip);
+       if (ret)
+               return ret;
+
+       ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0);
+       mutex_unlock(&chip->lock);
+
+       return ret;
+}
+
+static ssize_t tsl2563_adc1_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = tsl2563_get_adc(chip);
+       if (ret)
+               return ret;
+
+       ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1);
+       mutex_unlock(&chip->lock);
+
+       return ret;
+}
+
+/* Apply calibration coefficient to ADC count. */
+static u32 calib_adc(u32 adc, u32 calib)
+{
+       unsigned long scaled = adc;
+
+       scaled *= calib;
+       scaled >>= CALIB_FRAC_BITS;
+
+       return (u32) scaled;
+}
+
+static ssize_t tsl2563_lux_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       u32 calib0, calib1;
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = tsl2563_get_adc(chip);
+       if (ret)
+               goto out;
+
+       calib0 = calib_adc(chip->data0, chip->calib0);
+       calib1 = calib_adc(chip->data1, chip->calib1);
+
+       ret = snprintf(buf, PAGE_SIZE, "%d\n", adc_to_lux(calib0, calib1));
+
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+static ssize_t format_calib(char *buf, int len, u32 calib)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", calib_to_sysfs(calib));
+}
+
+static ssize_t tsl2563_calib0_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&chip->lock);
+       ret = format_calib(buf, PAGE_SIZE, chip->calib0);
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+static ssize_t tsl2563_calib1_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&chip->lock);
+       ret = format_calib(buf, PAGE_SIZE, chip->calib1);
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+static int do_calib_store(struct device *dev, const char *buf, size_t len,
+                         int ch)
+{
+       struct tsl2563_chip *chip = dev_get_drvdata(dev);
+       int value;
+       u32 calib;
+
+       if (1 != sscanf(buf, "%d", &value))
+               return -EINVAL;
+
+       calib = calib_from_sysfs(value);
+
+       if (ch)
+               chip->calib1 = calib;
+       else
+               chip->calib0 = calib;
+
+       return len;
+}
+
+static ssize_t tsl2563_calib0_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t len)
+{
+       return do_calib_store(dev, buf, len, 0);
+}
+
+static ssize_t tsl2563_calib1_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t len)
+{
+       return do_calib_store(dev, buf, len, 1);
+}
+
+static DEVICE_ATTR(adc0, S_IRUGO, tsl2563_adc0_show, NULL);
+static DEVICE_ATTR(adc1, S_IRUGO, tsl2563_adc1_show, NULL);
+static DEVICE_ATTR(lux, S_IRUGO, tsl2563_lux_show, NULL);
+static DEVICE_ATTR(calib0, S_IRUGO | S_IWUSR,
+                  tsl2563_calib0_show, tsl2563_calib0_store);
+static DEVICE_ATTR(calib1, S_IRUGO | S_IWUSR,
+                  tsl2563_calib1_show, tsl2563_calib1_store);
+
+static struct attribute *tsl2563_attributes[] = {
+       &dev_attr_adc0.attr,
+       &dev_attr_adc1.attr,
+       &dev_attr_lux.attr,
+       &dev_attr_calib0.attr,
+       &dev_attr_calib1.attr,
+       NULL
+};
+
+static const struct attribute_group tsl2563_group = {
+       .attrs = tsl2563_attributes,
+};
+
+static int tsl2563_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+
+       return sysfs_create_group(&dev->kobj, &tsl2563_group);
+}
+
+static void tsl2563_unregister_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+
+       sysfs_remove_group(&dev->kobj, &tsl2563_group);
+}
+
+/*--------------------------------------------------------------*/
+/*                      Probe, Attach, Remove                   */
+/*--------------------------------------------------------------*/
+static struct i2c_driver tsl2563_i2c_driver;
+
+static int tsl2563_probe(struct i2c_client *client,
+               const struct i2c_device_id *device_id)
+{
+       struct tsl2563_chip *chip;
+       int err = 0;
+       u8 id;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       err = tsl2563_detect(chip);
+       if (err) {
+               dev_err(&client->dev, "device not found, error %d \n", -err);
+               goto fail1;
+       }
+
+       err = tsl2563_read_id(chip, &id);
+       if (err)
+               goto fail1;
+
+       mutex_init(&chip->lock);
+
+       /* Default values used until userspace says otherwise */
+       chip->low_thres = 0x0;
+       chip->high_thres = 0xffff;
+       chip->gainlevel = tsl2563_gainlevel_table;
+       chip->intr = TSL2563_INT_PERSIST(4);
+       chip->calib0 = calib_from_sysfs(CALIB_BASE_SYSFS);
+       chip->calib1 = calib_from_sysfs(CALIB_BASE_SYSFS);
+
+       dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f);
+
+       err = tsl2563_configure(chip);
+       if (err)
+               goto fail1;
+
+       chip->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(chip->hwmon_dev))
+               goto fail1;
+
+       err = tsl2563_register_sysfs(client);
+       if (err) {
+               dev_err(&client->dev, "sysfs registration failed, %d\n", err);
+               goto fail2;
+       }
+
+       return 0;
+fail2:
+       hwmon_device_unregister(chip->hwmon_dev);
+fail1:
+       kfree(chip);
+       return err;
+}
+
+static int tsl2563_remove(struct i2c_client *client)
+{
+       struct tsl2563_chip *chip = i2c_get_clientdata(client);
+
+       tsl2563_unregister_sysfs(client);
+       hwmon_device_unregister(chip->hwmon_dev);
+
+       kfree(chip);
+       return 0;
+}
+
+static int tsl2563_suspend(struct i2c_client *client, pm_message_t state)
+{
+       struct tsl2563_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = tsl2563_set_power(chip, 0);
+       if (ret)
+               goto out;
+
+       chip->state = state;
+
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+static int tsl2563_resume(struct i2c_client *client)
+{
+       struct tsl2563_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = tsl2563_set_power(chip, 1);
+       if (ret)
+               goto out;
+
+       ret = tsl2563_configure(chip);
+       if (ret)
+               goto out;
+
+       chip->state.event = PM_EVENT_ON;
+
+out:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+
+static const struct i2c_device_id tsl2563_id[] = {
+       { DRIVER_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, tsl2563_id);
+
+static struct i2c_driver tsl2563_i2c_driver = {
+       .driver = {
+               .name    = DRIVER_NAME,
+       },
+       .suspend        = tsl2563_suspend,
+       .resume         = tsl2563_resume,
+       .probe          = tsl2563_probe,
+       .remove         = __devexit_p(tsl2563_remove),
+       .id_table       = tsl2563_id,
+};
+
+static int __init tsl2563_init(void)
+{
+       return i2c_add_driver(&tsl2563_i2c_driver);
+}
+
+static void __exit tsl2563_exit(void)
+{
+       i2c_del_driver(&tsl2563_i2c_driver);
+}
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("tsl2563 light sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(tsl2563_init);
+module_exit(tsl2563_exit);
diff --git a/drivers/i2c/chips/twl4030-madc.c b/drivers/i2c/chips/twl4030-madc.c
new file mode 100644 (file)
index 0000000..c17c7fe
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * drivers/i2c/chips/twl4030-madc.c
+ *
+ * TWL4030 MADC module driver
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl4030-madc.h>
+
+#include <asm/uaccess.h>
+
+#define TWL4030_MADC_PFX       "twl4030-madc: "
+
+struct twl4030_madc_data {
+       struct device           *dev;
+       struct mutex            lock;
+       struct work_struct      ws;
+       struct twl4030_madc_request     requests[TWL4030_MADC_NUM_METHODS];
+       int imr;
+       int isr;
+};
+
+static struct twl4030_madc_data *the_madc;
+
+static
+const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
+       [TWL4030_MADC_RT] = {
+               .sel    = TWL4030_MADC_RTSELECT_LSB,
+               .avg    = TWL4030_MADC_RTAVERAGE_LSB,
+               .rbase  = TWL4030_MADC_RTCH0_LSB,
+       },
+       [TWL4030_MADC_SW1] = {
+               .sel    = TWL4030_MADC_SW1SELECT_LSB,
+               .avg    = TWL4030_MADC_SW1AVERAGE_LSB,
+               .rbase  = TWL4030_MADC_GPCH0_LSB,
+               .ctrl   = TWL4030_MADC_CTRL_SW1,
+       },
+       [TWL4030_MADC_SW2] = {
+               .sel    = TWL4030_MADC_SW2SELECT_LSB,
+               .avg    = TWL4030_MADC_SW2AVERAGE_LSB,
+               .rbase  = TWL4030_MADC_GPCH0_LSB,
+               .ctrl   = TWL4030_MADC_CTRL_SW2,
+       },
+};
+
+static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
+{
+       int ret;
+       u8 val;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
+       if (ret) {
+               dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
+               return ret;
+       }
+
+       return val;
+}
+
+static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
+{
+       int ret;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
+       if (ret)
+               dev_err(madc->dev, "unable to write register 0x%X\n", reg);
+}
+
+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
+{
+       u8 msb, lsb;
+
+       /* For each ADC channel, we have MSB and LSB register pair. MSB address
+        * is always LSB address+1. reg parameter is the addr of LSB register */
+       msb = twl4030_madc_read(madc, reg + 1);
+       lsb = twl4030_madc_read(madc, reg);
+
+       return (int)(((msb << 8) | lsb) >> 6);
+}
+
+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
+               u8 reg_base, u16 channels, int *buf)
+{
+       int count = 0;
+       u8 reg, i;
+
+       if (unlikely(!buf))
+               return 0;
+
+       for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
+               if (channels & (1<<i)) {
+                       reg = reg_base + 2*i;
+                       buf[i] = twl4030_madc_channel_raw_read(madc, reg);
+                       count++;
+               }
+       }
+       return count;
+}
+
+static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
+{
+       u8 val;
+
+       val = twl4030_madc_read(madc, madc->imr);
+       val &= ~(1 << id);
+       twl4030_madc_write(madc, madc->imr, val);
+}
+
+static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
+{
+       u8 val;
+
+       val = twl4030_madc_read(madc, madc->imr);
+       val |= (1 << id);
+       twl4030_madc_write(madc, madc->imr, val);
+}
+
+static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
+{
+       struct twl4030_madc_data *madc = _madc;
+       u8 isr_val, imr_val;
+       int i;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       /* Use COR to ack interrupts since we have no shared IRQs in ISRx */
+       isr_val = twl4030_madc_read(madc, madc->isr);
+       imr_val = twl4030_madc_read(madc, madc->imr);
+
+       isr_val &= ~imr_val;
+
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+               if (!(isr_val & (1<<i)))
+                       continue;
+
+               twl4030_madc_disable_irq(madc, i);
+               madc->requests[i].result_pending = 1;
+       }
+
+       schedule_work(&madc->ws);
+
+       return IRQ_HANDLED;
+}
+
+static void twl4030_madc_work(struct work_struct *ws)
+{
+       const struct twl4030_madc_conversion_method *method;
+       struct twl4030_madc_data *madc;
+       struct twl4030_madc_request *r;
+       int len, i;
+
+       madc = container_of(ws, struct twl4030_madc_data, ws);
+       mutex_lock(&madc->lock);
+
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+
+               r = &madc->requests[i];
+
+               /* No pending results for this method, move to next one */
+               if (!r->result_pending)
+                       continue;
+
+               method = &twl4030_conversion_methods[r->method];
+
+               /* Read results */
+               len = twl4030_madc_read_channels(madc, method->rbase,
+                                                r->channels, r->rbuf);
+
+               /* Return results to caller */
+               if (r->func_cb != NULL) {
+                       r->func_cb(len, r->channels, r->rbuf);
+                       r->func_cb = NULL;
+               }
+
+               /* Free request */
+               r->result_pending = 0;
+               r->active         = 0;
+       }
+
+       mutex_unlock(&madc->lock);
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+               struct twl4030_madc_request *req)
+{
+       struct twl4030_madc_request *p;
+
+       p = &madc->requests[req->method];
+
+       memcpy(p, req, sizeof *req);
+
+       twl4030_madc_enable_irq(madc, req->method);
+
+       return 0;
+}
+
+static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+               int conv_method)
+{
+       const struct twl4030_madc_conversion_method *method;
+
+       method = &twl4030_conversion_methods[conv_method];
+
+       switch (conv_method) {
+       case TWL4030_MADC_SW1:
+       case TWL4030_MADC_SW2:
+               twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
+               break;
+       case TWL4030_MADC_RT:
+       default:
+               break;
+       }
+}
+
+static void twl4030_madc_wait_conversion_ready_ms(
+               struct twl4030_madc_data *madc,
+               u8 *time, u8 status_reg)
+{
+       u8 reg = 0;
+
+       do {
+               msleep(1);
+               (*time)--;
+               reg = twl4030_madc_read(madc, status_reg);
+       } while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
+                 (*time != 0));
+}
+
+int twl4030_madc_conversion(struct twl4030_madc_request *req)
+{
+       const struct twl4030_madc_conversion_method *method;
+       u8 wait_time, ch_msb, ch_lsb;
+       int ret;
+
+       if (unlikely(!req))
+               return -EINVAL;
+
+       /* Do we have a conversion request ongoing */
+       if (the_madc->requests[req->method].active)
+               return -EBUSY;
+
+       ch_msb = (req->channels >> 8) & 0xff;
+       ch_lsb = req->channels & 0xff;
+
+       method = &twl4030_conversion_methods[req->method];
+
+       mutex_lock(&the_madc->lock);
+
+       /* Select channels to be converted */
+       twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
+       twl4030_madc_write(the_madc, method->sel, ch_lsb);
+
+       /* Select averaging for all channels if do_avg is set */
+       if (req->do_avg) {
+               twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
+               twl4030_madc_write(the_madc, method->avg, ch_lsb);
+       }
+
+       if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
+               twl4030_madc_set_irq(the_madc, req);
+               twl4030_madc_start_conversion(the_madc, req->method);
+               the_madc->requests[req->method].active = 1;
+               ret = 0;
+               goto out;
+       }
+
+       /* With RT method we should not be here anymore */
+       if (req->method == TWL4030_MADC_RT) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       twl4030_madc_start_conversion(the_madc, req->method);
+       the_madc->requests[req->method].active = 1;
+
+       /* Wait until conversion is ready (ctrl register returns EOC) */
+       wait_time = 50;
+       twl4030_madc_wait_conversion_ready_ms(the_madc,
+                       &wait_time, method->ctrl);
+       if (wait_time == 0) {
+               dev_dbg(the_madc->dev, "conversion timeout!\n");
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
+                                        req->rbuf);
+
+       the_madc->requests[req->method].active = 0;
+
+out:
+       mutex_unlock(&the_madc->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_madc_conversion);
+
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+               int chan, int on)
+{
+       int ret;
+       u8 regval;
+
+       /* Current generator is only available for ADCIN0 and ADCIN1. NB:
+        * ADCIN1 current generator only works when AC or VBUS is present */
+       if (chan > 1)
+               return EINVAL;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                                 &regval, TWL4030_BCI_BCICTL1);
+       if (on)
+               regval |= (chan) ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+       else
+               regval &= (chan) ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+                                  regval, TWL4030_BCI_BCICTL1);
+
+       return ret;
+}
+
+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
+{
+       u8 regval;
+
+       regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
+       if (on)
+               regval |= TWL4030_MADC_MADCON;
+       else
+               regval &= ~TWL4030_MADC_MADCON;
+       twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
+
+       return 0;
+}
+
+static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
+                             unsigned int cmd, unsigned long arg)
+{
+       struct twl4030_madc_user_parms par;
+       int val, ret;
+
+       ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
+       if (ret) {
+               dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
+               return -EACCES;
+       }
+
+       switch (cmd) {
+       case TWL4030_MADC_IOCX_ADC_RAW_READ: {
+               struct twl4030_madc_request req;
+               if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
+                       return -EINVAL;
+
+               req.channels = (1 << par.channel);
+               req.do_avg      = par.average;
+               req.method      = TWL4030_MADC_SW1;
+               req.func_cb     = NULL;
+
+               val = twl4030_madc_conversion(&req);
+               if (val <= 0) {
+                       par.status = -1;
+               } else {
+                       par.status = 0;
+                       par.result = (u16)req.rbuf[par.channel];
+               }
+               break;
+                                            }
+       default:
+               return -EINVAL;
+       }
+
+       ret = copy_to_user((void __user *) arg, &par, sizeof(par));
+       if (ret) {
+               dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+static struct file_operations twl4030_madc_fileops = {
+       .owner = THIS_MODULE,
+       .ioctl = twl4030_madc_ioctl
+};
+
+static struct miscdevice twl4030_madc_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "twl4030-madc",
+       .fops = &twl4030_madc_fileops
+};
+
+static int __init twl4030_madc_probe(struct platform_device *pdev)
+{
+       struct twl4030_madc_data *madc;
+       struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+       u8 regval;
+
+       madc = kzalloc(sizeof *madc, GFP_KERNEL);
+       if (!madc)
+               return -ENOMEM;
+
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "platform_data not available\n");
+               ret = -EINVAL;
+               goto err_pdata;
+       }
+
+       madc->imr = (pdata->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+       madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
+       ret = misc_register(&twl4030_madc_device);
+       if (ret) {
+               dev_dbg(&pdev->dev, "could not register misc_device\n");
+               goto err_misc;
+       }
+       twl4030_madc_set_power(madc, 1);
+       twl4030_madc_set_current_generator(madc, 0, 1);
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                                 &regval, TWL4030_BCI_BCICTL1);
+
+       regval |= TWL4030_BCI_MESBAT;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE,
+                                  regval, TWL4030_BCI_BCICTL1);
+
+       ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler,
+                         0, "twl4030_madc", madc);
+       if (ret) {
+               dev_dbg(&pdev->dev, "could not request irq\n");
+               goto err_irq;
+       }
+
+       platform_set_drvdata(pdev, madc);
+       mutex_init(&madc->lock);
+       INIT_WORK(&madc->ws, twl4030_madc_work);
+
+       the_madc = madc;
+
+       return 0;
+
+err_irq:
+       misc_deregister(&twl4030_madc_device);
+
+err_misc:
+err_pdata:
+       kfree(madc);
+
+       return ret;
+}
+
+static int __exit twl4030_madc_remove(struct platform_device *pdev)
+{
+       struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+
+       twl4030_madc_set_power(madc, 0);
+       twl4030_madc_set_current_generator(madc, 0, 0);
+       free_irq(TWL4030_MODIRQ_MADC, madc);
+       cancel_work_sync(&madc->ws);
+       misc_deregister(&twl4030_madc_device);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_madc_driver = {
+       .probe          = twl4030_madc_probe,
+       .remove         = __exit_p(twl4030_madc_remove),
+       .driver         = {
+               .name   = "twl4030_madc",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init twl4030_madc_init(void)
+{
+       return platform_driver_register(&twl4030_madc_driver);
+}
+module_init(twl4030_madc_init);
+
+static void __exit twl4030_madc_exit(void)
+{
+       platform_driver_unregister(&twl4030_madc_driver);
+}
+module_exit(twl4030_madc_exit);
+
+MODULE_ALIAS("platform:twl4030-madc");
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("twl4030 ADC driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/i2c/chips/twl4030-power.c b/drivers/i2c/chips/twl4030-power.c
new file mode 100644 (file)
index 0000000..cb325b0
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * linux/drivers/i2c/chips/twl4030-power.c
+ *
+ * Handle TWL4030 Power initialization
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2006 Texas Instruments, Inc
+ *
+ * Written by  Kalle Jokiniemi
+ *             Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/i2c/twl4030.h>
+
+#include <asm/mach-types.h>
+
+#define PWR_P1_SW_EVENTS       0x10
+#define PWR_DEVOFF     (1<<0)
+
+#define PHY_TO_OFF_PM_MASTER(p)                (p - 0x36)
+#define PHY_TO_OFF_PM_RECIEVER(p)      (p - 0x5b)
+
+/* resource - hfclk */
+#define R_HFCLKOUT_DEV_GRP     PHY_TO_OFF_PM_RECIEVER(0xe6)
+
+/* PM events */
+#define R_P1_SW_EVENTS         PHY_TO_OFF_PM_MASTER(0x46)
+#define R_P2_SW_EVENTS         PHY_TO_OFF_PM_MASTER(0x47)
+#define R_P3_SW_EVENTS         PHY_TO_OFF_PM_MASTER(0x48)
+#define R_CFG_P1_TRANSITION    PHY_TO_OFF_PM_MASTER(0x36)
+#define R_CFG_P2_TRANSITION    PHY_TO_OFF_PM_MASTER(0x37)
+#define R_CFG_P3_TRANSITION    PHY_TO_OFF_PM_MASTER(0x38)
+
+#define LVL_WAKEUP     0x08
+
+#define ENABLE_WARMRESET (1<<4)
+
+/* sequence script */
+
+#define END_OF_SCRIPT          0x3f
+
+#define R_SEQ_ADD_A2S          PHY_TO_OFF_PM_MASTER(0x55)
+#define R_SEQ_ADD_SA12         PHY_TO_OFF_PM_MASTER(0x56)
+#define        R_SEQ_ADD_S2A3          PHY_TO_OFF_PM_MASTER(0x57)
+#define        R_SEQ_ADD_WARM          PHY_TO_OFF_PM_MASTER(0x58)
+#define R_MEMORY_ADDRESS       PHY_TO_OFF_PM_MASTER(0x59)
+#define R_MEMORY_DATA          PHY_TO_OFF_PM_MASTER(0x5a)
+
+/* Power bus message definitions */
+
+#define DEV_GRP_NULL           0x0
+#define DEV_GRP_P1             0x1
+#define DEV_GRP_P2             0x2
+#define DEV_GRP_P3             0x4
+
+#define RES_GRP_RES            0x0
+#define RES_GRP_PP             0x1
+#define RES_GRP_RC             0x2
+#define RES_GRP_PP_RC          0x3
+#define RES_GRP_PR             0x4
+#define RES_GRP_PP_PR          0x5
+#define RES_GRP_RC_PR          0x6
+#define RES_GRP_ALL            0x7
+
+#define RES_TYPE2_R0           0x0
+
+#define RES_TYPE_ALL           0x7
+
+#define RES_STATE_WRST         0xF
+#define RES_STATE_ACTIVE       0xE
+#define RES_STATE_SLEEP                0x8
+#define RES_STATE_OFF          0x0
+
+/*
+*      Power Bus Message Format
+*
+*      Broadcast Message (16 Bits)
+*      DEV_GRP[15:13] MT[12]  RES_GRP[11:9]  RES_TYPE2[8:7] RES_TYPE[6:4]
+*      RES_STATE[3:0]
+*
+*      Singular Message (16 Bits)
+*      DEV_GRP[15:13] MT[12]  RES_ID[11:4]  RES_STATE[3:0]
+*
+*/
+
+#define MSG_BROADCAST(devgrp, grp, type, type2, state) \
+       (devgrp << 13 | 1 << 12 | grp << 9 | type2 << 7 | type << 4 | state)
+
+#define MSG_SINGULAR(devgrp, id, state) \
+       (devgrp << 13 | 0 << 12 | id << 4 | state)
+
+#define R_PROTECT_KEY          0x0E
+#define KEY_1                  0xC0
+#define KEY_2                  0x0C
+
+struct triton_ins {
+       u16 pmb_message;
+       u8 delay;
+};
+
+
+#define CONFIG_DISABLE_HFCLK   1
+
+#if defined(CONFIG_MACH_OMAP_3430SDP) || defined(CONFIG_MACH_OMAP_3430LABRADOR)
+
+struct triton_ins sleep_on_seq[] __initdata = {
+       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 4},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+#ifdef CONFIG_DISABLE_HFCLK
+       {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 3},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 3},
+#endif /* #ifdef CONFIG_DISABLE_HFCLK */
+};
+
+struct triton_ins sleep_off_seq[] __initdata = {
+#ifndef CONFIG_DISABLE_HFCLK
+       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 4},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+#else
+       {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 0x30},
+       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 0x30},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 0x37},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 3},
+#endif /* #ifndef CONFIG_DISABLE_HFCLK */
+};
+
+struct triton_ins t2_wrst_seq[] __initdata = {
+       {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+       {MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+       {MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+       {MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+#else
+struct triton_ins sleep_on_seq[] __initdata = {
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0,
+                       RES_STATE_SLEEP), 4},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
+                       RES_STATE_SLEEP), 4},
+};
+
+struct triton_ins sleep_off_seq[] __initdata = {
+       {MSG_SINGULAR(DEV_GRP_NULL, 0x17, RES_STATE_ACTIVE), 0x30},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP_PR, RES_TYPE_ALL, RES_TYPE2_R0,
+                       RES_STATE_ACTIVE), 0x37},
+       {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, RES_TYPE_ALL, RES_TYPE2_R0,
+                       RES_STATE_ACTIVE), 0x2},
+};
+
+struct triton_ins t2_wrst_seq[] __initdata = { };
+
+#endif
+
+static int __init twl4030_write_script_byte(u8 address, u8 byte)
+{
+       int err;
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, address,
+                                       R_MEMORY_ADDRESS);
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, byte,
+                                       R_MEMORY_DATA);
+
+       return err;
+}
+
+static int __init twl4030_write_script_ins(u8 address, u16 pmb_message,
+                                               u8 delay, u8 next)
+{
+       int err = 0;
+
+       address *= 4;
+       err |= twl4030_write_script_byte(address++, pmb_message >> 8);
+       err |= twl4030_write_script_byte(address++, pmb_message & 0xff);
+       err |= twl4030_write_script_byte(address++, delay);
+       err |= twl4030_write_script_byte(address++, next);
+
+       return err;
+}
+
+static int __init twl4030_write_script(u8 address, struct triton_ins *script,
+                                       int len)
+{
+       int err = 0;
+
+       for (; len; len--, address++, script++) {
+               if (len == 1)
+                       err |= twl4030_write_script_ins(address,
+                                                       script->pmb_message,
+                                                       script->delay,
+                                                       END_OF_SCRIPT);
+               else
+                       err |= twl4030_write_script_ins(address,
+                                                       script->pmb_message,
+                                                       script->delay,
+                                                       address + 1);
+       }
+
+       return err;
+}
+
+static int __init config_sleep_wake_sequence(void)
+{
+       int err = 0;
+
+       /*
+        * CLKREQ is pulled high on the 2430SDP, therefore, we need to take
+        * it out of the HFCLKOUT DEV_GRP for P1 else HFCLKOUT can't be stopped.
+        */
+
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+                                 0x20, R_HFCLKOUT_DEV_GRP);
+
+       /* Set ACTIVE to SLEEP SEQ address in T2 memory*/
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2B,
+                                 R_SEQ_ADD_A2S);
+
+       /* Set SLEEP to ACTIVE SEQ address for P1 and P2 */
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2F,
+                                 R_SEQ_ADD_SA12);
+
+       /* Set SLEEP to ACTIVE SEQ address for P3 */
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x2F,
+                                 R_SEQ_ADD_S2A3);
+
+       /* Install Active->Sleep (A2S) sequence */
+       err |= twl4030_write_script(0x2B, sleep_on_seq,
+                                       ARRAY_SIZE(sleep_on_seq));
+
+       /* Install Sleep->Active (S2A) sequence */
+       err |= twl4030_write_script(0x2F, sleep_off_seq,
+                                       ARRAY_SIZE(sleep_off_seq));
+
+       if (machine_is_omap_3430sdp() || machine_is_omap_ldp()) {
+               u8 data;
+               /* Disabling AC charger effect on sleep-active transitions */
+               err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
+                                               R_CFG_P1_TRANSITION);
+               data &= ~(1<<1);
+               err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, data ,
+                                               R_CFG_P1_TRANSITION);
+       }
+
+       /* P1/P2/P3 LVL_WAKEUP should be on LEVEL */
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+                                       R_P1_SW_EVENTS);
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+                                       R_P2_SW_EVENTS);
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, LVL_WAKEUP,
+                               R_P3_SW_EVENTS);
+
+       if (err)
+               printk(KERN_ERR "TWL4030 sleep-wake sequence config error\n");
+
+       return err;
+}
+
+
+/* Programming the WARMRESET Sequence on TRITON */
+static int __init config_warmreset_sequence(void)
+{
+
+       int e = 0;
+       u8 rd_data;
+
+       if (!ARRAY_SIZE(t2_wrst_seq))
+               return 0;
+
+       /* Set WARM RESET SEQ address for P1 */
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x38,
+                               R_SEQ_ADD_WARM);
+
+       /* Install Warm Reset sequence */
+       e |= twl4030_write_script(0x38, t2_wrst_seq,
+                                       ARRAY_SIZE(t2_wrst_seq));
+
+       /* P1/P2/P3 enable WARMRESET */
+       e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+                               R_P1_SW_EVENTS);
+       rd_data |= ENABLE_WARMRESET;
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+                               R_P1_SW_EVENTS);
+
+       e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+                               R_P2_SW_EVENTS);
+       rd_data |= ENABLE_WARMRESET;
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+                               R_P2_SW_EVENTS);
+
+       e |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &rd_data,
+                               R_P3_SW_EVENTS);
+       rd_data |= ENABLE_WARMRESET;
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, rd_data,
+                               R_P3_SW_EVENTS);
+
+       if (e)
+               printk(KERN_ERR
+                       "TWL4030 Power Companion Warmreset seq config error\n");
+       return e;
+}
+
+static int __init twl4030_power_init(void)
+{
+       int err = 0;
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
+                               R_PROTECT_KEY);
+       err |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
+                               R_PROTECT_KEY);
+
+       if (err)
+               return err;
+
+       err = config_sleep_wake_sequence();
+       if (err)
+               return err;
+
+       err = config_warmreset_sequence();
+       if (err)
+               return err;
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+
+       return err;
+
+}
+
+module_init(twl4030_power_init);
diff --git a/drivers/i2c/chips/twl4030-poweroff.c b/drivers/i2c/chips/twl4030-poweroff.c
new file mode 100644 (file)
index 0000000..0ebab0b
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * linux/drivers/i2c/chips/twl4030_poweroff.c
+ *
+ * Power off device
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_P1_SW_EVENTS       0x10
+#define PWR_DEVOFF     (1<<0)
+
+static void twl4030_poweroff(void)
+{
+       u8 val;
+       int err;
+
+       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+                                 PWR_P1_SW_EVENTS);
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while reading TWL4030"
+                                       "PM_MASTER P1_SW_EVENTS\n", err);
+               return ;
+       }
+
+       val |= PWR_DEVOFF;
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+                                  PWR_P1_SW_EVENTS);
+
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while writing TWL4030"
+                                       "PM_MASTER P1_SW_EVENTS\n", err);
+               return ;
+       }
+
+       return;
+}
+
+static int __init twl4030_poweroff_init(void)
+{
+       pm_power_off = twl4030_poweroff;
+
+       return 0;
+}
+
+static void __exit twl4030_poweroff_exit(void)
+{
+       pm_power_off = NULL;
+}
+
+module_init(twl4030_poweroff_init);
+module_exit(twl4030_poweroff_exit);
+
+MODULE_ALIAS("i2c:twl4030-poweroff");
+MODULE_DESCRIPTION("Triton2 device power off");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
diff --git a/drivers/i2c/chips/twl4030-pwrbutton.c b/drivers/i2c/chips/twl4030-pwrbutton.c
new file mode 100644 (file)
index 0000000..9a361b3
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * drivers/i2c/chips/twl4030-pwrbutton.c
+ *
+ * Driver for sending triton2 power button event to input-layer
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_ISR1 0
+#define PWR_IMR1 1
+#define PWR_PWRON_IRQ (1<<0)
+
+#define PWR_EDR1 5
+#define PWR_PWRON_RISING (1<<1)
+#define PWR_PWRON_FALLING  (1<<0)
+#define PWR_PWRON_BOTH (PWR_PWRON_RISING | PWR_PWRON_FALLING)
+
+#define PWR_SIH_CTRL 7
+
+#define STS_HW_CONDITIONS 0xf
+
+static struct input_dev *powerbutton_dev;
+
+static irqreturn_t powerbutton_irq(int irq, void *dev_id)
+{
+       int err;
+       u8 value;
+
+       err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
+                                 STS_HW_CONDITIONS);
+       if (!err)  {
+               input_report_key(powerbutton_dev, KEY_POWER,
+                                value & PWR_PWRON_IRQ);
+       } else {
+               pr_err("twl4030: i2c error %d while reading TWL4030"
+                       " PM_MASTER STS_HW_CONDITIONS register\n", err);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int __init twl4030_pwrbutton_init(void)
+{
+       int err = 0;
+       u8 value;
+
+       if (request_irq(TWL4030_PWRIRQ_PWRBTN, powerbutton_irq, 0,
+                       "PwrButton", NULL) < 0) {
+               printk(KERN_ERR "Unable to allocate IRQ for power button\n");
+               err = -EBUSY;
+               goto out;
+       }
+
+       powerbutton_dev = input_allocate_device();
+       if (!powerbutton_dev) {
+               printk(KERN_ERR
+                       "Unable to allocate input device for power button\n");
+               err = -ENOMEM;
+               goto free_irq_and_out;
+       }
+
+       powerbutton_dev->evbit[0] = BIT_MASK(EV_KEY);
+       powerbutton_dev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+       powerbutton_dev->name = "triton2-pwrbutton";
+
+       err = input_register_device(powerbutton_dev);
+       if (err) {
+               input_free_device(powerbutton_dev);
+               goto free_irq_and_out;
+       }
+
+       err = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &value, PWR_IMR1);
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while reading TWL4030"
+                                       " INT PWR_IMR1 register\n", err);
+
+               goto free_input_dev;
+       }
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+                                  value & (~PWR_PWRON_IRQ), PWR_IMR1);
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while writing TWL4030"
+                                   " INT PWR_IMR1 register\n", err);
+               goto free_input_dev;
+       }
+
+       err = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &value, PWR_EDR1);
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while reading TWL4030"
+                                       " INT PWR_EDR1 register\n", err);
+               goto free_input_dev;
+       }
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+                                  value | PWR_PWRON_BOTH, PWR_EDR1);
+
+       if (err) {
+               printk(KERN_WARNING "I2C error %d while writing TWL4030"
+                                       " INT PWR_EDR1 register\n", err);
+               goto free_input_dev;
+       }
+
+       printk(KERN_INFO "triton2 power button driver initialized\n");
+
+       return 0;
+
+
+free_input_dev:
+       input_unregister_device(powerbutton_dev);
+free_irq_and_out:
+       free_irq(TWL4030_PWRIRQ_PWRBTN, NULL);
+out:
+       return err;
+}
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+       free_irq(TWL4030_PWRIRQ_PWRBTN, NULL);
+       input_unregister_device(powerbutton_dev);
+       input_free_device(powerbutton_dev);
+
+}
+
+module_init(twl4030_pwrbutton_init);
+module_exit(twl4030_pwrbutton_exit);
+
+MODULE_ALIAS("i2c:twl4030-pwrbutton");
+MODULE_DESCRIPTION("Triton2 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver");
+
diff --git a/drivers/i2c/chips/twl4030-pwrirq.c b/drivers/i2c/chips/twl4030-pwrirq.c
new file mode 100644 (file)
index 0000000..1ef3b7e
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * twl4030-pwrirq.c - handle power interrupts from TWL3040
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/random.h>
+#include <linux/kthread.h>
+#include <linux/i2c/twl4030.h>
+
+
+static u8 twl4030_pwrirq_mask;
+static u8 twl4030_pwrirq_pending_unmask;
+
+static struct task_struct *twl4030_pwrirq_unmask_thread;
+
+static void twl4030_pwrirq_ack(unsigned int irq) {}
+
+static void twl4030_pwrirq_disableint(unsigned int irq) {}
+
+static void twl4030_pwrirq_enableint(unsigned int irq)
+{
+       twl4030_pwrirq_pending_unmask |= 1 << (irq - TWL4030_PWR_IRQ_BASE);
+       if (twl4030_pwrirq_unmask_thread &&
+               twl4030_pwrirq_unmask_thread->state != TASK_RUNNING)
+               wake_up_process(twl4030_pwrirq_unmask_thread);
+}
+
+static struct irq_chip twl4030_pwrirq_chip = {
+       .name   = "twl4030-pwr",
+       .ack    = twl4030_pwrirq_ack,
+       .mask   = twl4030_pwrirq_disableint,
+       .unmask = twl4030_pwrirq_enableint,
+};
+
+static void do_twl4030_pwrmodule_irq(unsigned int irq, irq_desc_t *desc)
+{
+       struct irqaction *action;
+       const unsigned int cpu = smp_processor_id();
+
+       desc->status |= IRQ_LEVEL;
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               action = desc->action;
+               if (action) {
+                       int ret;
+                       int status = 0;
+                       int retval = 0;
+
+                       do {
+                               ret = action->handler(irq, action->dev_id);
+                               if (ret == IRQ_HANDLED)
+                                       status |= action->flags;
+                               retval |= ret;
+                               action = action->next;
+                       } while (action);
+
+                       if (status & IRQF_SAMPLE_RANDOM)
+                               add_interrupt_randomness(irq);
+
+                       if (retval != IRQ_HANDLED)
+                               printk(KERN_ERR "ISR for TWL4030 power module"
+                                       " irq %d can't handle interrupt\n",
+                                       irq);
+               } else {
+                       local_irq_disable();
+                       twl4030_pwrirq_mask |= 1 << (irq - TWL4030_PWR_IRQ_BASE);
+                       local_irq_enable();
+                       twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+                                            twl4030_pwrirq_mask,
+                                            TWL4030_INT_PWR_IMR1);
+               }
+       }
+}
+
+static void do_twl4030_pwrirq(unsigned int irq, irq_desc_t *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       desc->status |= IRQ_LEVEL;
+
+       desc->chip->ack(irq);
+
+       if (!desc->depth) {
+               int ret;
+               int module_irq;
+               u8 pwr_isr;
+
+               kstat_cpu(cpu).irqs[irq]++;
+
+               local_irq_enable();
+               ret = twl4030_i2c_read_u8(TWL4030_MODULE_INT, &pwr_isr,
+                                         TWL4030_INT_PWR_ISR1);
+               if (ret) {
+                       printk(KERN_WARNING
+                               "I2C error %d while reading TWL4030"
+                               "INT PWR_ISR1 register\n", ret);
+                       return;
+               }
+
+               for (module_irq = TWL4030_PWR_IRQ_BASE; pwr_isr != 0;
+                       module_irq++, pwr_isr >>= 1) {
+                       if (pwr_isr & 1) {
+                               irq_desc_t *d = irq_desc + module_irq;
+                               d->handle_irq(module_irq, d);
+                       }
+               }
+
+               local_irq_disable();
+               desc->chip->unmask(irq);
+       }
+}
+
+static int twl4030_pwrirq_thread(void *data)
+{
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               u8 local_unmask;
+
+               local_irq_disable();
+               local_unmask = twl4030_pwrirq_pending_unmask;
+               twl4030_pwrirq_pending_unmask = 0;
+               local_irq_enable();
+
+               twl4030_pwrirq_mask &= ~local_unmask;
+
+               twl4030_i2c_write_u8(TWL4030_MODULE_INT, twl4030_pwrirq_mask,
+                                    TWL4030_INT_PWR_IMR1);
+
+               local_irq_disable();
+               if (!twl4030_pwrirq_pending_unmask)
+                       set_current_state(TASK_INTERRUPTIBLE);
+               local_irq_enable();
+
+               schedule();
+       }
+       set_current_state(TASK_RUNNING);
+       return 0;
+}
+
+static int __init twl4030_pwrirq_init(void)
+{
+       int i, err;
+
+       twl4030_pwrirq_mask = 0xff;
+       twl4030_pwrirq_pending_unmask = 0;
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_INT, twl4030_pwrirq_mask,
+                                       TWL4030_INT_PWR_IMR1);
+       if (err)
+               return err;
+
+       /* Enable clear on read */
+
+       err = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+                               TWL4030_SIH_CTRL_COR_MASK,
+                               TWL4030_INT_PWR_SIH_CTRL);
+       if (err)
+               return err;
+
+       twl4030_pwrirq_unmask_thread = kthread_create(twl4030_pwrirq_thread,
+               NULL, "twl4030 pwrirq");
+       if (!twl4030_pwrirq_unmask_thread) {
+               printk(KERN_ERR
+                       "%s: could not create twl4030 pwrirq unmask thread!\n",
+                               __func__);
+               return -ENOMEM;
+       }
+
+       for (i = TWL4030_PWR_IRQ_BASE; i < TWL4030_PWR_IRQ_END; i++) {
+               set_irq_chip(i, &twl4030_pwrirq_chip);
+               set_irq_handler(i, do_twl4030_pwrmodule_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       set_irq_chained_handler(TWL4030_MODIRQ_PWR, do_twl4030_pwrirq);
+
+       return 0;
+}
+subsys_initcall(twl4030_pwrirq_init);
+
+static void __exit twl4030_pwrirq_exit(void)
+{
+
+       int i;
+
+       /* FIXME the irqs are left enabled; trouble when they arrive... */
+
+       set_irq_handler(TWL4030_MODIRQ_PWR, NULL);
+       set_irq_flags(TWL4030_MODIRQ_PWR, 0);
+
+       for (i = TWL4030_PWR_IRQ_BASE; i < TWL4030_PWR_IRQ_END; i++) {
+               set_irq_handler(i, NULL);
+               set_irq_flags(i, 0);
+       }
+
+       if (twl4030_pwrirq_unmask_thread) {
+               kthread_stop(twl4030_pwrirq_unmask_thread);
+               twl4030_pwrirq_unmask_thread = NULL;
+       }
+}
+module_exit(twl4030_pwrirq_exit);
diff --git a/drivers/i2c/chips/twl4030-usb.c b/drivers/i2c/chips/twl4030-usb.c
new file mode 100644 (file)
index 0000000..61c831c
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Current status:
+ *     - HS USB ULPI mode works.
+ *     - 3-pin mode support may be added in future.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c/twl4030.h>
+#include <mach/usb.h>
+
+/* Register defines */
+
+#define VENDOR_ID_LO                   0x00
+#define VENDOR_ID_HI                   0x01
+#define PRODUCT_ID_LO                  0x02
+#define PRODUCT_ID_HI                  0x03
+
+#define FUNC_CTRL                      0x04
+#define FUNC_CTRL_SET                  0x05
+#define FUNC_CTRL_CLR                  0x06
+#define FUNC_CTRL_SUSPENDM             (1 << 6)
+#define FUNC_CTRL_RESET                        (1 << 5)
+#define FUNC_CTRL_OPMODE_MASK          (3 << 3) /* bits 3 and 4 */
+#define FUNC_CTRL_OPMODE_NORMAL                (0 << 3)
+#define FUNC_CTRL_OPMODE_NONDRIVING    (1 << 3)
+#define FUNC_CTRL_OPMODE_DISABLE_BIT_NRZI      (2 << 3)
+#define FUNC_CTRL_TERMSELECT           (1 << 2)
+#define FUNC_CTRL_XCVRSELECT_MASK      (3 << 0) /* bits 0 and 1 */
+#define FUNC_CTRL_XCVRSELECT_HS                (0 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS                (1 << 0)
+#define FUNC_CTRL_XCVRSELECT_LS                (2 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS4LS     (3 << 0)
+
+#define IFC_CTRL                       0x07
+#define IFC_CTRL_SET                   0x08
+#define IFC_CTRL_CLR                   0x09
+#define IFC_CTRL_INTERFACE_PROTECT_DISABLE     (1 << 7)
+#define IFC_CTRL_AUTORESUME            (1 << 4)
+#define IFC_CTRL_CLOCKSUSPENDM         (1 << 3)
+#define IFC_CTRL_CARKITMODE            (1 << 2)
+#define IFC_CTRL_FSLSSERIALMODE_3PIN   (1 << 1)
+
+#define TWL4030_OTG_CTRL               0x0A
+#define TWL4030_OTG_CTRL_SET           0x0B
+#define TWL4030_OTG_CTRL_CLR           0x0C
+#define TWL4030_OTG_CTRL_DRVVBUS       (1 << 5)
+#define TWL4030_OTG_CTRL_CHRGVBUS      (1 << 4)
+#define TWL4030_OTG_CTRL_DISCHRGVBUS   (1 << 3)
+#define TWL4030_OTG_CTRL_DMPULLDOWN    (1 << 2)
+#define TWL4030_OTG_CTRL_DPPULLDOWN    (1 << 1)
+#define TWL4030_OTG_CTRL_IDPULLUP      (1 << 0)
+
+#define USB_INT_EN_RISE                        0x0D
+#define USB_INT_EN_RISE_SET            0x0E
+#define USB_INT_EN_RISE_CLR            0x0F
+#define USB_INT_EN_FALL                        0x10
+#define USB_INT_EN_FALL_SET            0x11
+#define USB_INT_EN_FALL_CLR            0x12
+#define USB_INT_STS                    0x13
+#define USB_INT_LATCH                  0x14
+#define USB_INT_IDGND                  (1 << 4)
+#define USB_INT_SESSEND                        (1 << 3)
+#define USB_INT_SESSVALID              (1 << 2)
+#define USB_INT_VBUSVALID              (1 << 1)
+#define USB_INT_HOSTDISCONNECT         (1 << 0)
+
+#define CARKIT_CTRL                    0x19
+#define CARKIT_CTRL_SET                        0x1A
+#define CARKIT_CTRL_CLR                        0x1B
+#define CARKIT_CTRL_MICEN              (1 << 6)
+#define CARKIT_CTRL_SPKRIGHTEN         (1 << 5)
+#define CARKIT_CTRL_SPKLEFTEN          (1 << 4)
+#define CARKIT_CTRL_RXDEN              (1 << 3)
+#define CARKIT_CTRL_TXDEN              (1 << 2)
+#define CARKIT_CTRL_IDGNDDRV           (1 << 1)
+#define CARKIT_CTRL_CARKITPWR          (1 << 0)
+#define CARKIT_PLS_CTRL                        0x22
+#define CARKIT_PLS_CTRL_SET            0x23
+#define CARKIT_PLS_CTRL_CLR            0x24
+#define CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN       (1 << 3)
+#define CARKIT_PLS_CTRL_SPKRLEFT_BIASEN        (1 << 2)
+#define CARKIT_PLS_CTRL_RXPLSEN                (1 << 1)
+#define CARKIT_PLS_CTRL_TXPLSEN                (1 << 0)
+
+#define MCPC_CTRL                      0x30
+#define MCPC_CTRL_SET                  0x31
+#define MCPC_CTRL_CLR                  0x32
+#define MCPC_CTRL_RTSOL                        (1 << 7)
+#define MCPC_CTRL_EXTSWR               (1 << 6)
+#define MCPC_CTRL_EXTSWC               (1 << 5)
+#define MCPC_CTRL_VOICESW              (1 << 4)
+#define MCPC_CTRL_OUT64K               (1 << 3)
+#define MCPC_CTRL_RTSCTSSW             (1 << 2)
+#define MCPC_CTRL_HS_UART              (1 << 0)
+
+#define MCPC_IO_CTRL                   0x33
+#define MCPC_IO_CTRL_SET               0x34
+#define MCPC_IO_CTRL_CLR               0x35
+#define MCPC_IO_CTRL_MICBIASEN         (1 << 5)
+#define MCPC_IO_CTRL_CTS_NPU           (1 << 4)
+#define MCPC_IO_CTRL_RXD_PU            (1 << 3)
+#define MCPC_IO_CTRL_TXDTYP            (1 << 2)
+#define MCPC_IO_CTRL_CTSTYP            (1 << 1)
+#define MCPC_IO_CTRL_RTSTYP            (1 << 0)
+
+#define MCPC_CTRL2                     0x36
+#define MCPC_CTRL2_SET                 0x37
+#define MCPC_CTRL2_CLR                 0x38
+#define MCPC_CTRL2_MCPC_CK_EN          (1 << 0)
+
+#define OTHER_FUNC_CTRL                        0x80
+#define OTHER_FUNC_CTRL_SET            0x81
+#define OTHER_FUNC_CTRL_CLR            0x82
+#define OTHER_FUNC_CTRL_BDIS_ACON_EN   (1 << 4)
+#define OTHER_FUNC_CTRL_FIVEWIRE_MODE  (1 << 2)
+
+#define OTHER_IFC_CTRL                 0x83
+#define OTHER_IFC_CTRL_SET             0x84
+#define OTHER_IFC_CTRL_CLR             0x85
+#define OTHER_IFC_CTRL_OE_INT_EN       (1 << 6)
+#define OTHER_IFC_CTRL_CEA2011_MODE    (1 << 5)
+#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN     (1 << 4)
+#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT      (1 << 3)
+#define OTHER_IFC_CTRL_HIZ_ULPI                (1 << 2)
+#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0)
+
+#define OTHER_INT_EN_RISE              0x86
+#define OTHER_INT_EN_RISE_SET          0x87
+#define OTHER_INT_EN_RISE_CLR          0x88
+#define OTHER_INT_EN_FALL              0x89
+#define OTHER_INT_EN_FALL_SET          0x8A
+#define OTHER_INT_EN_FALL_CLR          0x8B
+#define OTHER_INT_STS                  0x8C
+#define OTHER_INT_LATCH                        0x8D
+#define OTHER_INT_VB_SESS_VLD          (1 << 7)
+#define OTHER_INT_DM_HI                        (1 << 6) /* not valid for "latch" reg */
+#define OTHER_INT_DP_HI                        (1 << 5) /* not valid for "latch" reg */
+#define OTHER_INT_BDIS_ACON            (1 << 3) /* not valid for "fall" regs */
+#define OTHER_INT_MANU                 (1 << 1)
+#define OTHER_INT_ABNORMAL_STRESS      (1 << 0)
+
+#define ID_STATUS                      0x96
+#define ID_RES_FLOAT                   (1 << 4)
+#define ID_RES_440K                    (1 << 3)
+#define ID_RES_200K                    (1 << 2)
+#define ID_RES_102K                    (1 << 1)
+#define ID_RES_GND                     (1 << 0)
+
+#define POWER_CTRL                     0xAC
+#define POWER_CTRL_SET                 0xAD
+#define POWER_CTRL_CLR                 0xAE
+#define POWER_CTRL_OTG_ENAB            (1 << 5)
+
+#define OTHER_IFC_CTRL2                        0xAF
+#define OTHER_IFC_CTRL2_SET            0xB0
+#define OTHER_IFC_CTRL2_CLR            0xB1
+#define OTHER_IFC_CTRL2_ULPI_STP_LOW   (1 << 4)
+#define OTHER_IFC_CTRL2_ULPI_TXEN_POL  (1 << 3)
+#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK    (3 << 0) /* bits 0 and 1 */
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N   (0 << 0)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N   (1 << 0)
+
+#define REG_CTRL_EN                    0xB2
+#define REG_CTRL_EN_SET                        0xB3
+#define REG_CTRL_EN_CLR                        0xB4
+#define REG_CTRL_ERROR                 0xB5
+#define ULPI_I2C_CONFLICT_INTEN                (1 << 0)
+
+#define OTHER_FUNC_CTRL2               0xB8
+#define OTHER_FUNC_CTRL2_SET           0xB9
+#define OTHER_FUNC_CTRL2_CLR           0xBA
+#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0)
+
+/* following registers do not have separate _clr and _set registers */
+#define VBUS_DEBOUNCE                  0xC0
+#define ID_DEBOUNCE                    0xC1
+#define VBAT_TIMER                     0xD3
+#define PHY_PWR_CTRL                   0xFD
+#define PHY_PWR_PHYPWD                 (1 << 0)
+#define PHY_CLK_CTRL                   0xFE
+#define PHY_CLK_CTRL_CLOCKGATING_EN    (1 << 2)
+#define PHY_CLK_CTRL_CLK32K_EN         (1 << 1)
+#define REQ_PHY_DPLL_CLK               (1 << 0)
+#define PHY_CLK_CTRL_STS               0xFF
+#define PHY_DPLL_CLK                   (1 << 0)
+
+/* In module TWL4030_MODULE_PM_MASTER */
+#define PROTECT_KEY                    0x0E
+
+/* In module TWL4030_MODULE_PM_RECEIVER */
+#define VUSB_DEDICATED1                        0x7D
+#define VUSB_DEDICATED2                        0x7E
+#define VUSB1V5_DEV_GRP                        0x71
+#define VUSB1V5_TYPE                   0x72
+#define VUSB1V5_REMAP                  0x73
+#define VUSB1V8_DEV_GRP                        0x74
+#define VUSB1V8_TYPE                   0x75
+#define VUSB1V8_REMAP                  0x76
+#define VUSB3V1_DEV_GRP                        0x77
+#define VUSB3V1_TYPE                   0x78
+#define VUSB3V1_REMAP                  0x79
+
+/* In module TWL4030_MODULE_INTBR */
+#define PMBR1                          0x0D
+#define GPIO_USB_4PIN_ULPI_2430C       (3 << 0)
+
+/* In module TWL4030_MODULE_INT */
+#define REG_PWR_ISR1                   0x00
+#define REG_PWR_IMR1                   0x01
+#define USB_PRES                       (1 << 2)
+#define REG_PWR_EDR1                   0x05
+#define USB_PRES_FALLING               (1 << 4)
+#define USB_PRES_RISING                        (1 << 5)
+#define REG_PWR_SIH_CTRL               0x07
+#define COR                            (1 << 2)
+
+/* bits in OTG_CTRL */
+#define        OTG_XCEIV_OUTPUTS \
+       (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
+#define        OTG_XCEIV_INPUTS \
+       (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID)
+#define        OTG_CTRL_BITS \
+       (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP)
+       /* and OTG_PULLUP is sometimes written */
+
+#define        OTG_CTRL_MASK   (OTG_DRIVER_SEL| \
+       OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \
+       OTG_CTRL_BITS)
+
+
+struct twl4030_usb {
+       struct work_struct      irq_work;
+       struct otg_transceiver  otg;
+       struct device           *dev;
+
+       /* for vbus reporting with irqs disabled */
+       spinlock_t              lock;
+
+       /* pin configuration */
+       enum twl4030_usb_mode   usb_mode;
+
+       unsigned                vbus:1;
+       int                     irq;
+       u8                      asleep;
+};
+
+/* internal define on top of container_of */
+#define xceiv_to_twl(x)                container_of((x), struct twl4030_usb, otg);
+
+/*-------------------------------------------------------------------------*/
+
+static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
+               u8 module, u8 data, u8 address)
+{
+       u8 check;
+
+       if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+           (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+                                               (check == data))
+               return 0;
+       /* Failed once: Try again */
+       if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+           (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+                                               (check == data))
+               return 0;
+       /* Failed again: Return error */
+
+       return -EBUSY;
+}
+
+#define twl4030_usb_write_verify(twl, address, data)   \
+       twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address))
+
+static inline int twl4030_usb_write(struct twl4030_usb *twl,
+               u8 address, u8 data)
+{
+       int ret = 0;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address);
+       if (ret >= 0) {
+#if 0  /* debug */
+               u8 data1;
+               if (twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data1,
+                                       address) < 0)
+                       dev_err(twl->dev, "re-read failed\n");
+               else
+                       dev_dbg(twl->dev,
+                              "Write %s wrote %x read %x from reg %x\n",
+                              (data1 == data) ? "succeed" : "mismatch",
+                              data, data1, address);
+#endif
+       } else {
+               dev_warn(twl->dev,
+                       "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+       }
+
+       return ret;
+}
+
+static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address)
+{
+       u8 data;
+       int ret = 0;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data, address);
+       if (ret >= 0)
+               ret = data;
+       else
+               dev_warn(twl->dev,
+                       "TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
+
+       return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+       return twl4030_usb_write(twl, reg + 1, bits);
+}
+
+static inline int
+twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+       return twl4030_usb_write(twl, reg + 2, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
+{
+       twl->usb_mode = mode;
+
+       switch (mode) {
+       case T2_USB_MODE_ULPI:
+               twl4030_usb_clear_bits(twl, IFC_CTRL, IFC_CTRL_CARKITMODE);
+               twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+               twl4030_usb_clear_bits(twl, FUNC_CTRL,
+                                       FUNC_CTRL_XCVRSELECT_MASK |
+                                       FUNC_CTRL_OPMODE_MASK);
+               break;
+/*
+       case T2_USB_MODE_CEA2011_3PIN:
+               twl4030_cea2011_3_pin_FS_setup(twl);
+               break;
+*/
+       default:
+               /* FIXME: power on defaults */
+               break;
+       };
+}
+
+static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
+{
+       unsigned long timeout;
+       int val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+
+       if (val >= 0) {
+               if (on) {
+                       /* enable DPLL to access PHY registers over I2C */
+                       val |= REQ_PHY_DPLL_CLK;
+                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+                                               (u8)val) < 0);
+
+                       timeout = jiffies + HZ;
+                       while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+                                                       PHY_DPLL_CLK)
+                               && time_before(jiffies, timeout))
+                                       udelay(10);
+                       if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+                                                       PHY_DPLL_CLK))
+                               dev_err(twl->dev, "Timeout setting T2 HSUSB "
+                                               "PHY DPLL clock\n");
+               } else {
+                       /* let ULPI control the DPLL clock */
+                       val &= ~REQ_PHY_DPLL_CLK;
+                       WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+                                               (u8)val) < 0);
+               }
+       }
+}
+
+static void usb_irq_enable(struct twl4030_usb *twl, int rising, int falling)
+{
+       u8 val;
+
+       /* edge setup */
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &val, REG_PWR_EDR1) < 0);
+
+       val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
+       if (rising)
+               val = val | USB_PRES_RISING;
+       if (falling)
+               val = val | USB_PRES_FALLING;
+       WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+                               val, REG_PWR_EDR1) < 0);
+
+       /* un-mask interrupt */
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &val, REG_PWR_IMR1) < 0);
+
+       val &= ~USB_PRES;
+
+       WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+                               val, REG_PWR_IMR1) < 0);
+}
+
+static void usb_irq_disable(struct twl4030_usb *twl)
+{
+       u8 val;
+
+       /* undo edge setup */
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &val, REG_PWR_EDR1) < 0);
+       val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
+       WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+                               val, REG_PWR_EDR1) < 0);
+
+       /* mask interrupt */
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &val, REG_PWR_IMR1) < 0);
+       val |= USB_PRES;
+
+       WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+                               val, REG_PWR_IMR1) < 0);
+}
+
+static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+       u8 pwr;
+
+       pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
+       if (on) {
+               pwr &= ~PHY_PWR_PHYPWD;
+               WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+               twl4030_usb_write(twl, PHY_CLK_CTRL,
+                                 twl4030_usb_read(twl, PHY_CLK_CTRL) |
+                                       (PHY_CLK_CTRL_CLOCKGATING_EN |
+                                               PHY_CLK_CTRL_CLK32K_EN));
+       } else  {
+               pwr |= PHY_PWR_PHYPWD;
+               WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+       }
+}
+
+static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off)
+{
+       if (controller_off)
+               usb_irq_disable(twl);
+
+       if (twl->asleep)
+               return;
+
+       if (!controller_off)
+               /* enable rising edge interrupt to detect cable attach */
+               usb_irq_enable(twl, 1, 0);
+
+       twl4030_phy_power(twl, 0);
+       twl->asleep = 1;
+}
+
+static void twl4030_phy_resume(struct twl4030_usb *twl)
+{
+       if (!twl->asleep)
+               return;
+
+       /* enable falling edge interrupt to detect cable detach */
+       usb_irq_enable(twl, 0, 1);
+
+       twl4030_phy_power(twl, 1);
+       twl4030_i2c_access(twl, 1);
+       twl4030_usb_set_mode(twl, twl->usb_mode);
+       if (twl->usb_mode == T2_USB_MODE_ULPI)
+               twl4030_i2c_access(twl, 0);
+       twl->asleep = 0;
+}
+
+static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+{
+       /* Enable writing to power configuration registers */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
+
+       /* put VUSB3V1 LDO in active state */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+
+       /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+
+       /* turn on 3.1V regulator */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+
+       /* turn on 1.5V regulator */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+
+       /* turn on 1.8V regulator */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+
+       /* disable access to power configuration registers */
+       twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+}
+
+static ssize_t twl4030_usb_vbus_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct twl4030_usb *twl = dev_get_drvdata(dev);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&twl->lock, flags);
+       ret = sprintf(buf, "%s\n", twl->vbus ? "on" : "off");
+       spin_unlock_irqrestore(&twl->lock, flags);
+
+       return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
+
+static void twl4030_usb_irq_work(struct work_struct *work)
+{
+       struct twl4030_usb *twl = container_of(work,
+                       struct twl4030_usb, irq_work);
+
+       sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+}
+
+static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
+{
+       struct twl4030_usb *twl = _twl;
+       u8 val;
+
+       /* action based on cable attach or detach */
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &val, REG_PWR_EDR1) < 0);
+
+       if (val & USB_PRES_RISING) {
+               twl4030_phy_resume(twl);
+               twl4030charger_usb_en(1);
+               twl->vbus = 1;
+       } else {
+               twl4030charger_usb_en(0);
+               twl->vbus = 0;
+               twl4030_phy_suspend(twl, 0);
+       }
+       schedule_work(&twl->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+{
+       struct twl4030_usb *twl = xceiv_to_twl(x);
+
+       if (suspend)
+               twl4030_phy_suspend(twl, 1);
+       else
+               twl4030_phy_resume(twl);
+
+       return 0;
+}
+
+static int twl4030_set_peripheral(struct otg_transceiver *x,
+               struct usb_gadget *gadget)
+{
+       struct twl4030_usb *twl;
+       u32 l;
+
+       if (!x)
+               return -ENODEV;
+
+       twl = xceiv_to_twl(x);
+
+       if (!gadget) {
+               omap_writew(0, OTG_IRQ_EN);
+               twl4030_phy_suspend(twl, 1);
+               twl->otg.gadget = NULL;
+
+               return -ENODEV;
+       }
+
+       twl->otg.gadget = gadget;
+       twl4030_phy_resume(twl);
+
+       l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
+       l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
+       l |= OTG_ID;
+       omap_writel(l, OTG_CTRL);
+
+       twl->otg.state = OTG_STATE_B_IDLE;
+
+       twl4030_usb_set_bits(twl, USB_INT_EN_RISE,
+                       USB_INT_SESSVALID | USB_INT_VBUSVALID);
+       twl4030_usb_set_bits(twl, USB_INT_EN_FALL,
+                       USB_INT_SESSVALID | USB_INT_VBUSVALID);
+
+       return 0;
+}
+
+static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+{
+       struct twl4030_usb *twl;
+
+       if (!x)
+               return -ENODEV;
+
+       twl = xceiv_to_twl(x);
+
+       if (!host) {
+               omap_writew(0, OTG_IRQ_EN);
+               twl4030_phy_suspend(twl, 1);
+               twl->otg.host = NULL;
+
+               return -ENODEV;
+       }
+
+       twl->otg.host = host;
+       twl4030_phy_resume(twl);
+
+       twl4030_usb_set_bits(twl, TWL4030_OTG_CTRL,
+                       TWL4030_OTG_CTRL_DMPULLDOWN
+                               | TWL4030_OTG_CTRL_DPPULLDOWN);
+       twl4030_usb_set_bits(twl, USB_INT_EN_RISE, USB_INT_IDGND);
+       twl4030_usb_set_bits(twl, USB_INT_EN_FALL, USB_INT_IDGND);
+       twl4030_usb_set_bits(twl, FUNC_CTRL, FUNC_CTRL_SUSPENDM);
+       twl4030_usb_set_bits(twl, TWL4030_OTG_CTRL, TWL4030_OTG_CTRL_DRVVBUS);
+
+       return 0;
+}
+
+static int __init twl4030_usb_probe(struct platform_device *pdev)
+{
+       struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+       struct twl4030_usb      *twl;
+       int status;
+       u8                      vbus;
+
+       twl = kzalloc(sizeof *twl, GFP_KERNEL);
+       if (!twl)
+               return -ENOMEM;
+
+       if (!pdata) {
+               dev_info(&pdev->dev, "platform_data not available\n");
+               return -EINVAL;
+       }
+
+       WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                               &vbus, REG_PWR_EDR1) < 0);
+       vbus &= USB_PRES_RISING;
+
+       twl->dev                = &pdev->dev;
+       twl->irq                = platform_get_irq(pdev, 0);
+       twl->otg.set_host       = twl4030_set_host;
+       twl->otg.set_peripheral = twl4030_set_peripheral;
+       twl->otg.set_suspend    = twl4030_set_suspend;
+       twl->usb_mode           = pdata->usb_mode;
+       twl->vbus               = vbus ? 1 : 0;
+
+       /* init spinlock for workqueue */
+       spin_lock_init(&twl->lock);
+
+       /* init irq workqueue before request_irq */
+       INIT_WORK(&twl->irq_work, twl4030_usb_irq_work);
+
+       usb_irq_disable(twl);
+       status = request_irq(twl->irq, twl4030_usb_irq, 0, "twl4030_usb", twl);
+       if (status < 0) {
+               dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
+                       twl->irq, status);
+               kfree(twl);
+               return status;
+       }
+
+       twl4030_usb_ldo_init(twl);
+       twl4030_phy_power(twl, 1);
+       twl4030_i2c_access(twl, 1);
+       twl4030_usb_set_mode(twl, twl->usb_mode);
+
+       twl->asleep = 0;
+
+       if (twl->usb_mode == T2_USB_MODE_ULPI) {
+               twl4030_i2c_access(twl, 0);
+               twl4030_phy_suspend(twl, 0);
+       }
+
+       otg_set_transceiver(&twl->otg);
+       platform_set_drvdata(pdev, twl);
+       dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
+
+       if (device_create_file(&pdev->dev, &dev_attr_vbus))
+               dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+       return 0;
+}
+
+static int __exit twl4030_usb_remove(struct platform_device *pdev)
+{
+       struct twl4030_usb *twl = platform_get_drvdata(pdev);
+       int val;
+
+       usb_irq_disable(twl);
+       free_irq(twl->irq, twl);
+       device_remove_file(twl->dev, &dev_attr_vbus);
+
+       /* set transceiver mode to power on defaults */
+       twl4030_usb_set_mode(twl, -1);
+
+       /* autogate 60MHz ULPI clock,
+        * clear dpll clock request for i2c access,
+        * disable 32KHz
+        */
+       val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+       if (val >= 0) {
+               val |= PHY_CLK_CTRL_CLOCKGATING_EN;
+               val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
+               twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val);
+       }
+
+       /* disable complete OTG block */
+       twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+       twl4030_phy_power(twl, 0);
+
+       kfree(twl);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_driver = {
+       .probe          = twl4030_usb_probe,
+       .remove         = __exit_p(twl4030_remove),
+       .driver         = {
+               .name   = "twl4030_usb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init twl4030_usb_init(void)
+{
+       return platform_driver_register(&twl4030_driver);
+}
+subsys_initcall(twl4030_usb_init);
+
+static void __exit twl4030_usb_exit(void)
+{
+       platform_driver_unregister(&twl4030_driver);
+}
+module_exit(twl4030_usb_exit);
+
+MODULE_ALIAS("platform:twl4030_usb");
+MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation");
+MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
+MODULE_LICENSE("GPL");
index b346a687ab593a89834270e64b91f2b8b1c4c66f..f5201083bdc5c0bfde455a7365f929a18585326e 100644 (file)
@@ -978,7 +978,7 @@ static void __exit i2c_exit(void)
        bus_unregister(&i2c_bus_type);
 }
 
-subsys_initcall(i2c_init);
+postcore_initcall(i2c_init);
 module_exit(i2c_exit);
 
 /* ----------------------------------------------------
index efd70a9745910bfacd97e39b4fdebe451fa14ca4..e4d043679b41cf47b88ce8c43daa4068e6486a71 100644 (file)
@@ -259,6 +259,39 @@ config KEYBOARD_OMAP
          To compile this driver as a module, choose M here: the
          module will be called omap-keypad.
 
+config KEYBOARD_TWL4030
+       tristate "TI TWL4030 keypad support"
+       depends on TWL4030_CORE && (MACH_OMAP_2430SDP || MACH_OMAP2EVM || MACH_OMAP_3430SDP || MACH_OMAP3EVM)
+       help
+         Say Y here if you want to use the OMAP TWL4030 keypad.
+
+         To compile this driver as a module, choose M here: the
+         module will be called omap-twl4030keypad. This driver depends on
+         TWL4030 Core and TWL4030 GPIO I2C client driver
+
+config OMAP_PS2
+       tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support"
+       depends on ARCH_OMAP15XX && MACH_OMAP_INNOVATOR
+       help
+         Say Y here if you want to use the OMAP Innovator 1510 PS/2
+         keyboard and mouse.
+
+         To compile this driver as a module, choose M here: the
+         module will be called innovator_ps2.
+
+config KEYBOARD_TSC2301
+       tristate "TSC2301 keypad support"
+       depends on SPI_TSC2301
+       help
+         Say Y here for if you are using the keypad features of TSC2301.
+
+config KEYBOARD_LM8323
+       tristate "LM8323 keypad chip"
+       depends on I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LM8323 keypad controller.
+
 config KEYBOARD_PXA27x
        tristate "PXA27x/PXA3xx keypad support"
        depends on PXA27x || PXA3xx
index 0edc8f285d1cf57f21a93eb4da8e6fa279920a7a..ae47fffacc6852798d0f094b078cb71d780125fc 100644 (file)
@@ -19,6 +19,10 @@ obj-$(CONFIG_KEYBOARD_TOSA)          += tosakbd.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_TSC2301)         += tsc2301_kp.o
+obj-$(CONFIG_KEYBOARD_LM8323)          += lm8323.o
+obj-$(CONFIG_KEYBOARD_TWL4030)         += omap-twl4030keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)          += pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
diff --git a/drivers/input/keyboard/innovator_ps2.c b/drivers/input/keyboard/innovator_ps2.c
new file mode 100644 (file)
index 0000000..5f88839
--- /dev/null
@@ -0,0 +1,1279 @@
+/*
+ * drivers/char/innovator_ps2.c
+ *
+ * Basic PS/2 keyboard/mouse driver for the Juno® USAR HID controller
+ * present on the TI Innovator/OMAP1510 Break-out-board.
+ *
+ *
+ * Author: MontaVista Software, Inc.
+ *         <gdavis@mvista.com> or <source@mvista.com>
+ *
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ *
+ * REFERENCES:
+ *
+ * 1.  Technical Reference Manual
+ *     Juno® 01
+ *     Multi-function ICs family
+ *     UR8HC007-001 HID & Power management controller
+ *     Document Number: DOC8-007-001-TR-075
+ *     Date: February 2002
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     http://www.semtech.com/pdf/doc8-007-001-tr.pdf
+ *
+ * 2.  Juno® 01 UR8HC007-001 Data Sheet
+ *     Extremely Low-power Input Device and Power Management IC
+ *     Copyright Â©1998-2002 Semtech Corporation
+ *     DOC8-007-001-DS-112
+ *     http://www.semtech.com/pdf/doc8-007-001-ds.pdf
+ *
+ *
+ * HISTORY:
+ *
+ * 20030626: George G. Davis <gdavis@mvista.com>
+ *      Initially based on the following RidgeRun DSPlinux Version 1.6 files:
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.h
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_ps2.c
+ *             linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_spi.c
+ *     All original files above are
+ *             Copyright (C) 2001 RidgeRun, Inc.
+ *             Author: Alex McMains <aam@ridgerun.com>
+ *
+ * 20040812: Thiago Radicchi <trr@dcc.ufmg.br>
+ *      Cleanup of old code from 2.4 driver and some debug code.
+ *      Minor changes in interrupt handling code.
+ *
+ * NOTES:
+ *
+ * 1. This driver does not provide support for setting keyboard/mouse
+ *    configuration parameters. Both devices are managed directly by
+ *    the Juno UR8HC007-001 on behalf of the host. This minimises the
+ *    amount of host processing required to manage HID events and state
+ *    changes, e.g. both keyboard and mouse devices are hot pluggable
+ *    with no host intervention required. However, we cannot customise
+ *    keyboard/mouse settings in this case. So we live with the defaults
+ *    as setup by the Juno UR8HC007-001 whatever they may be.
+ * 2. Keyboard auto repeat does not work. See 1 above. : )
+ *
+ *
+ * TODO:
+ *
+ * 1. Complete DPM/LDM stubs and test.
+ * 2. Add SPI error handling support, i.e. resend, etc.,.
+ * 3. Determine why innovator_hid_interrupt() is called for every
+ *    invocation of Innovator FPGA IRQ demux. It appears that the
+ *    missed Innovator ethernet workaround may be to blame. However,
+ *    it does not adversely affect operation of this driver since we
+ *    check for assertion of ATN prior to servicing the interrupt. If
+ *    ATN is negated, we bug out right away.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/arch/fpga.h>
+
+#undef INNOVATOR_KEYB_DEBUG
+#ifdef INNOVATOR_KEYB_DEBUG
+#define        dbg(format, arg...) printk(KERN_DEBUG "%s:%d: " format , \
+                                  __FUNCTION__ , __LINE__ , ## arg)
+#define        entry() printk(KERN_DEBUG "%s:%d: Entry\n" , __FUNCTION__ , __LINE__)
+#define        exit()  printk(KERN_DEBUG "%s:%d: Exit\n" , __FUNCTION__ , __LINE__)
+#define dump_packet(p, n)                                      \
+       {                                                       \
+               int i;                                          \
+               printk(KERN_DEBUG "%s:%d: %08x:" ,              \
+                      __FUNCTION__ , __LINE__ , (int) p);      \
+               for (i = 0; i < n; i += 1) {                    \
+                       printk(" %02x", (int) p[i]);            \
+               }                                               \
+               printk("\n");                                   \
+       }
+#else
+#define        dbg(format, arg...) do {} while (0)
+#define        entry() do {} while (0)
+#define        exit()  do {} while (0)
+#define dump_packet(p, n) do {} while (0)
+#endif
+
+
+#define        PFX     "innovator_ps2"
+#define err(format, arg...)    printk(KERN_ERR PFX ": " format , ## arg)
+#define info(format, arg...)   printk(KERN_INFO PFX ": " format , ## arg)
+#define warn(format, arg...)   printk(KERN_WARNING PFX ": " format , ## arg)
+
+
+/****************************************************************************/
+
+/*
+ * Synchronous communications timing parameters (Reference [1] pg 7-7)
+ */
+
+#define tMSA   5000    /* -/5ms        _SS to _ATN (master transfer) */
+#define tMAC   100     /* 100us/5ms    _ATN to first clock pulse (master
+                                       transfer) */
+#define tMIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tSIB   150     /* 150us/5ms    Beginning of byte transfer to beginning
+                                       of next byte transfer */
+#define tMSP   100     /* -/100us      Last clock pulse of packet to _SS
+                                       de-assertion */
+#define tMNSA  100     /* -/100us      _SS de-assertion to _ATN de-assertion */
+#define tMNEXT 120     /* 120uS/-      _ATN release to _SS re-assertion
+                                       (master transfer) */
+#define        tSAS    5000    /* -/5ms        _ATN to _SS (slave transfer) */
+#define tSSC   100     /* 100us/5ms    _SS to first clock pulse (slave
+                                       transfer) */
+#define tSNA   100     /* -/100us      Last clock pulse of packet to _ATN
+                                       de-assertion */
+#define tSNAS  100     /* -/100us      _ATN release to _SS de-assertion */
+#define tSNEXT 120     /* 120us/-      _SS release to _ATN re-assertion
+                                       (slave transfer) */
+#define tSCK   4       /* 4us/-        Clock period */
+#define tSLOW  2       /* 2us/-        Clock LOW period */
+#define tHOLD  200     /* 200ns/-      Master data hold time */
+#define tSETUP 100     /* 100ns/-      Master data setup Time */
+#define tSSETUP        500     /* -/500ns      Slave data setup time from clock
+                                       falling edge */
+
+
+/*
+ * Protocol Headers (Reference [1], pg. 5-1):
+ */
+
+
+/* Protocols used in commands issued by the host: */
+#define SIMPLE                 0x80    /* Simple commands
+                                        * Common for both host and controller
+                                        * protocol headers.
+                                        */
+#define WRITE_REGISTER_BIT     0x81    /* Write register bit */
+#define READ_REGISTER_BIT      0x82    /* Read register bit */
+#define WRITE_REGISTER         0x83    /* Write register */
+#define READ_REGISTER          0x84    /* Read register */
+#define WRITE_BLOCK            0x85    /* Write block */
+#define READ_BLOCK             0x86    /* Read block */
+
+
+/* Protocols used in responses, reports and alerts issued by the controller: */
+#define REPORT_REGISTER_BIT    0x81    /* Report register bit & event alerts */
+#define REPORT_REGISTER                0x83    /* Report register */
+#define REPORT_BLOCK           0x85    /* Report block */
+#define POINTING_REPORT                0x87    /* Pointing device data report */
+#define KEYBOARD_REPORT                0x88    /* Keyboard device data report */
+
+
+/* Simple Commands (Reference [1], pg 5-3): */
+#define INITIALIZE             0x00    /* Forces the recipient to enter the
+                                        * known default power-on state.
+                                        */
+#define INITIALIZATION_COMPLETE        0x01    /* Issued as a hand-shake response only
+                                        * to the "Initialize" command.
+                                        */
+#define RESEND_REQUEST         0x05    /* Issued upon error in the reception
+                                        * of a package. The recipient resends
+                                        * the last transmitted packet.
+                                        */
+
+/* Register offsets (Reference [1], pg 6-1 thru 6-9): */
+
+#define REG_PM_COMM            0
+#define REG_PM_STATUS          1
+#define REG_PAGENO             255
+
+/* Power management bits ((Reference [1], pg 6-10): */
+
+#define SUS_STATE              0x2     /* in REG_PM_COMM */
+
+/* Miscellaneous constants: */
+
+#define X_MSB_SHIFT    (8-4)
+#define X_MSB_MASK     (3<<4)
+#define Y_MSB_SHIFT    (8-6)
+#define Y_MSB_MASK     (3<<6)
+
+
+#define JUNO_BLOCK_SIZE     32
+#define JUNO_BUFFER_SIZE    256
+
+
+/*
+ * Errors:
+ */
+
+#define E_BAD_HEADER   1
+#define E_BAD_LRC      2
+#define E_ZERO_BYTES   3
+#define E_BAD_VALUE    4
+#define E_BAD_MODE     5
+#define E_REPORT_MODE  6
+#define E_BAD_ACK      7
+#define E_BAD_DEVICE_ID        8
+#define E_PKT_SZ       9
+
+
+/*
+ * Host/Controller Command/Response Formats:
+ */
+
+typedef struct _simple_t {
+       u8 header;
+       u8 cmd_code;
+       u8 LRC;
+} __attribute__ ((packed)) simple_t;
+
+typedef struct _write_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) write_bit_t;
+
+typedef struct _read_bit_t {
+       u8 header;
+       u8 offset;
+       u8 bit;
+       u8 LRC;
+} __attribute__ ((packed)) read_bit_t;
+
+typedef struct _write_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) write_reg_t;
+
+typedef struct _read_reg_t {
+       u8 header;
+       u8 offset;
+       u8 LRC;
+} __attribute__ ((packed)) read_reg_t;
+
+typedef struct _write_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[JUNO_BLOCK_SIZE + 1]; /* Hack: LRC is last element of block[] */
+} __attribute__ ((packed)) write_block_t;
+
+typedef struct _read_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 LRC;
+} __attribute__ ((packed)) read_block_t;
+
+typedef struct _report_bit_t {
+       u8 header;
+       u8 offset;
+       u8 value_bit;
+       u8 LRC;
+} __attribute__ ((packed)) report_bit_t;
+
+typedef struct _report_reg_t {
+       u8 header;
+       u8 offset;
+       u8 value;
+       u8 LRC;
+} __attribute__ ((packed)) report_reg_t;
+
+typedef struct _report_block_t {
+       u8 header;
+       u8 offset;
+       u8 length;
+       u8 block[32];
+       u8 LRC;
+} __attribute__ ((packed)) report_block_t;
+
+typedef struct _mse_report_t {
+       u8 header;
+       u8 buttons;
+       u8 Xdisplacement;
+       u8 Ydisplacement;
+       u8 Zdisplacement;
+       u8 LRC;
+} __attribute__ ((packed)) mse_report_t;
+
+typedef struct _kdb_report_t {
+       u8 header;
+       u8 keynum;              /* up > 0x80, down < 0x7E, all keys up 0x00 */
+       u8 LRC;
+} __attribute__ ((packed)) kdb_report_t;
+
+
+static u8 buffer[JUNO_BUFFER_SIZE];
+
+static void do_hid_tasklet(unsigned long);
+DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0);
+static struct innovator_hid_dev *hid;
+
+struct innovator_hid_dev {
+       struct input_dev *mouse, *keyboard;
+       int open;
+       int irq_enabled;
+};
+
+/****************************************************************************/
+
+/*
+ * Low-level TI Innovator/OMAP1510 FPGA HID SPI interface helper functions:
+ */
+
+static u8
+innovator_fpga_hid_rd(void)
+{
+       u8 val = inb(INNOVATOR_FPGA_HID_SPI);
+       return val;
+}
+
+static void
+innovator_fpga_hid_wr(u8 val)
+{
+       outb(val, INNOVATOR_FPGA_HID_SPI);
+}
+
+static void
+innovator_fpga_hid_frob(u8 mask, u8 val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       innovator_fpga_hid_wr((innovator_fpga_hid_rd() & ~mask) | val);
+       local_irq_restore(flags);
+}
+
+static void
+innovator_fpga_hid_set_bits(u8 x)
+{
+       innovator_fpga_hid_frob(x, x);
+}
+
+static void
+SS(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_nSS, value ? OMAP1510_FPGA_HID_nSS : 0);
+}
+
+static void
+SCLK(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_SCLK, value ? OMAP1510_FPGA_HID_SCLK : 0);
+}
+
+static void
+MOSI(int value)
+{
+       innovator_fpga_hid_frob(OMAP1510_FPGA_HID_MOSI, value ? OMAP1510_FPGA_HID_MOSI : 0);
+}
+
+static u8
+MISO(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_MISO) ? 1 : 0);
+}
+
+static u8 
+ATN(void)
+{
+       return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_ATN) ? 1 : 0);
+}
+
+static int
+wait_for_ATN(int assert, int timeout)
+{
+       do {
+               if (ATN() == assert)
+                       return 0;
+               udelay(1);
+       } while (timeout -= 1);
+       return -1;
+}
+
+static u8
+innovator_fpga_hid_xfer_byte(u8 xbyte)
+{
+       int i;
+       u8 rbyte;
+
+       for (rbyte = 0, i = 7; i >= 0; i -= 1) {
+               SCLK(0);
+               MOSI((xbyte >> i) & 1);
+               udelay(tSLOW);
+               SCLK(1);
+               rbyte = (rbyte << 1) | MISO();
+               udelay(tSLOW);
+       }
+
+       return rbyte;
+}
+
+static void
+innovator_fpga_hid_reset(void)
+{
+       innovator_fpga_hid_wr(OMAP1510_FPGA_HID_SCLK | OMAP1510_FPGA_HID_MOSI);
+       mdelay(1);
+       innovator_fpga_hid_set_bits(OMAP1510_FPGA_HID_RESETn);
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1], Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation Host (master) packet
+  transmission timing, pg. 7-3, for timing and implementation details
+  for spi_xmt().
+
+ *****************************************************************************/
+
+int
+spi_xmt(u8 * p, u8 n)
+{
+       unsigned long flags;
+
+       dump_packet(p, n);
+       local_irq_save(flags);
+       disable_irq(OMAP1510_INT_FPGA_ATN);
+
+       if (ATN()) {
+               /* Oops, we have a collision. */
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is asserted\n");
+               return -EAGAIN;
+       }
+
+       SS(1);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               SS(0);
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN assertion\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMAC);
+
+       while (n--) {
+               innovator_fpga_hid_xfer_byte(*p++);
+               if (n) {
+                       udelay(tMIB - 8 * tSCK);
+               }
+       }
+
+       MOSI(1);        /* Set MOSI to idle high. */
+
+       /* NOTE: The data sheet does not specify a minimum delay
+        * here. But innovator_fpga_hid_xfer_byte() gives us a half-clock
+        * delay (tSLOW) after the last bit is sent. So I'm happy with
+        * that.
+        */
+
+       SS(0);
+
+       if (wait_for_ATN(0, tMNSA) < 0) {
+               enable_irq(OMAP1510_INT_FPGA_ATN);
+               local_irq_restore(flags);
+               dbg("timeout waiting for ATN negation\n");
+               return -EREMOTEIO;
+       }
+
+       udelay(tMNEXT);
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+       local_irq_restore(flags);
+       return 0;
+}
+
+
+/*****************************************************************************
+
+  Refer to Reference [1],  Chapter 7 / Low-level communications, Serial
+  Peripheral Interface (SPI) implementation, Slave packet transmission
+  timing, pg. 7-5, for timing and implementation details for spi_rcv().
+
+ *****************************************************************************/
+
+int
+spi_rcv(u8 * p, int len)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (len > 256) {
+               /* Limit packet size to something reasonable */
+               return -1;
+       }
+
+       local_irq_save(flags);
+
+       if (wait_for_ATN(1, tMSA) < 0) {
+               local_irq_restore(flags);
+               dbg("Protocol error: ATN is not asserted\n");
+               return -EREMOTEIO;
+       }
+
+       SS(1);
+
+       udelay(tSSC);
+
+       while (ATN()) {
+               if (ret >= len) {
+                       err("over run error\n");
+                       ret = -1;
+                       break;
+               }
+               p[ret++] = innovator_fpga_hid_xfer_byte(0xff);
+               udelay(tSNA);   /* Wait long enough to detect negation of ATN
+                                * after last clock pulse of packet.
+                                *
+                                * NOTE: Normally, we need a minimum delay of
+                                *       tSIB between the start of one byte
+                                *       and the start of the next. However,
+                                *       we also need to wait long enough
+                                *       for the USAR to negate ATN before
+                                *       starting the next byte. So we use
+                                *       max(tSIB - 8 * tSCK, tSNA) here to
+                                *       satisfy both constraints.
+                                */
+       }
+
+       SS(0);  /* NOTE: The data sheet does not specify a minimum delay
+                * here. But innovator_fpga_hid_xfer_byte() gives us a
+                * half-clock delay (tSLOW) after the last bit is sent. So
+                * I'm happy with that (rather than no delay at all : ).
+                */
+
+
+       udelay(tSNEXT); /* This isn't quite right. Assertion of ATN after
+                        * negation of SS is an USAR timing constraint.
+                        * What we need here is a spec for the minimum
+                        * delay from SS negation to SS assertion. But
+                        * for now, just use this brain dead delay.
+                        */
+
+       local_irq_restore(flags);
+
+       if (ret > 0) {
+               dump_packet(p, ret);
+       }
+
+       return ret;
+}
+
+
+/*****************************************************************************
+  Calculate Host/Controller Command/Response Longitudinal Redundancy Check (LRC)
+
+  The algorithm implemented in calculate_LRC() below is taken directly from
+  the reference [1], Chapter 7 / Low-level communications, LRC (Longitudinal
+  Redundancy Check), pg 5-10.
+
+ *****************************************************************************/
+
+static u8
+calculate_LRC(u8 * p, int n)
+{
+       u8 LRC;
+       int i;
+
+       /*
+        * Init the LRC using the first two message bytes.
+        */
+       LRC = p[0] ^ p[1];
+
+       /*
+        * Update the LRC using the remainder of the p.
+        */
+       for (i = 2; i < n; i++)
+               LRC ^= p[i];
+
+       /*
+        * If the MSB is set then clear the MSB and change the next
+        * most significant bit
+        */
+       if (LRC & 0x80)
+               LRC ^= 0xC0;
+
+       return LRC;
+}
+
+
+/*
+ * Controller response helper functions:
+ */
+
+static inline int
+report_mouse(mse_report_t * p, int n)
+{
+       if (p->header != POINTING_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(mse_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(mse_report_t) - 1)) ?
+               -E_BAD_LRC : POINTING_REPORT;
+}
+
+static inline int
+report_keyboard(kdb_report_t * p, int n)
+{
+       if (p->header != KEYBOARD_REPORT)
+               return -E_BAD_HEADER;
+
+       if (n != sizeof(kdb_report_t))
+               return -E_PKT_SZ;
+
+       return (p->LRC != calculate_LRC((u8 *) p, sizeof(kdb_report_t) - 1)) ?
+               -E_BAD_LRC : KEYBOARD_REPORT;
+}
+
+
+/*
+ * Miscellaneous helper functions:
+ */
+
+static inline int
+report_type(u8 * type)
+{
+       /* check the header to find out what kind of report it is */
+       if ((*type) == KEYBOARD_REPORT)
+               return KEYBOARD_REPORT;
+       else if ((*type) == POINTING_REPORT)
+               return POINTING_REPORT;
+       else
+               return -E_BAD_HEADER;
+}
+
+static inline int
+report_async(void * p, int n)
+{
+       int ret;
+
+       if ((ret = spi_rcv((u8 *) p, n)) < 0)
+               return ret;
+
+       if (report_type((u8 *) p) == POINTING_REPORT)
+               ret = report_mouse((mse_report_t *) p, ret);
+       else if (report_type((u8 *) p) == KEYBOARD_REPORT)
+               ret = report_keyboard((kdb_report_t *) p, ret);
+
+       return ret;
+}
+
+/*
+ * Host command helper functions:
+ */
+
+#if    0
+/* REVISIT/TODO: Wrapper for command/response with resend handing. */
+static int
+spi_xfer(u8 * optr, u8 osz, u8 * iptr, u8 isz)
+{
+       static u8 buf[256];
+       int ret;
+       int xretries = 3;
+
+       do {
+               if (optr != NULL && osz) {
+                       do {
+                               ret = spi_xmt((u8 *) optr, osz);
+                       } while (ret < 0);
+               }
+
+               ret = spi_rcv((u8 *) buf, 256);
+
+               if (ret == -EREMOTEIO) {
+                       if (iptr == NULL) {
+                               break;
+                       }
+               }
+       } while (xretries--);
+
+       return ret;
+}
+#endif
+
+/* REVISIT: Enable these when/if additional Juno features are required. */
+static inline int
+simple(u8 cmd)
+{
+       static simple_t p;
+       int ret;
+
+       p.header = SIMPLE;
+       p.cmd_code = cmd;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(p))
+               return -E_PKT_SZ;
+
+       if (p.header != SIMPLE)
+               return -E_BAD_HEADER;
+
+       if (p.LRC != calculate_LRC((u8 *) & p, sizeof(p) - 1))
+               return -E_BAD_LRC;
+
+       /* REVISIT: Need to check or return response code here? */
+}
+
+static inline int
+write_bit(u8 offset, u8 bit, u8 value)
+{
+       static write_bit_t p;
+
+       p.header = WRITE_REGISTER_BIT;
+       p.offset = offset;
+       p.value_bit = (bit << 1) | (value & 1);
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_bit(u8 offset, u8 bit, u8 * data)
+{
+       static read_bit_t p;
+       static report_bit_t q;
+       int ret;
+
+       p.header = READ_REGISTER_BIT;
+       p.offset = offset;
+       p.bit = bit;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER_BIT)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value_bit;
+
+       return 0;
+}
+
+static inline int
+write_reg(u8 offset, u8 value)
+{
+       static write_reg_t p;
+
+       p.header = WRITE_REGISTER;
+       p.offset = offset;
+       p.value = value;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       return spi_xmt((u8 *) & p, sizeof(p));
+}
+
+static inline int
+read_reg(u8 offset, u8 * data)
+{
+       static read_reg_t p;
+       static report_reg_t q;
+       int ret;
+
+       p.header = READ_REGISTER;
+       p.offset = offset;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(q))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_REGISTER)
+               return -E_BAD_HEADER;
+
+       if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1))
+               return -E_BAD_LRC;
+
+       *data = q.value;
+
+       return 0;
+}
+
+static inline int
+write_block(u8 offset, u8 length, u8 * block)
+{
+       static write_block_t p;
+
+       p.header = WRITE_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       memcpy(&p.block, block, length);
+       p.block[length] = calculate_LRC((u8 *) & p, 3 + length);
+
+       return spi_xmt((u8 *) & p, 4 + length);
+}
+
+static inline int
+read_block(u8 offset, u8 length, u8 * buf)
+{
+       static read_block_t p;
+       static report_block_t q;
+       int ret;
+
+       p.header = READ_BLOCK;
+       p.offset = offset;
+       p.length = length;
+       p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1);
+
+       if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0)
+               return ret;
+
+       if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0)
+               return ret;
+
+       if (ret == 0)
+               return -E_ZERO_BYTES;
+
+       if (ret != sizeof(4 + q.length))
+               return -E_PKT_SZ;
+
+       if (q.header != REPORT_BLOCK)
+               return -E_BAD_HEADER;
+
+       if (q.block[q.length] != calculate_LRC((u8 *) & q, 3 + q.length))
+               return -E_BAD_LRC;
+
+       if (length != q.length)
+               return -E_PKT_SZ;
+
+       memcpy(buf, &q.block, length);
+
+       return 0;
+}
+
+#ifdef INNOVATOR_KEYB_DEBUG
+static void
+ctrl_dump_regs(void)
+{
+       int i;
+       int n;
+
+       for (i = 0; i < 256; i += 8) {
+               read_block(i, 16, buffer);
+               mdelay(1);
+       }
+}
+#endif
+
+/*****************************************************************************/
+
+static void
+process_pointing_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       static int prev_x, prev_y, prev_btn;
+       int x, y, btn;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if (buffer[1] & (1 << 3)) {
+               /* relative pointing device report */
+               x = buffer[2];
+               y = buffer[3];
+
+               /* check the sign and convert from 2's complement if negative */
+               if (buffer[1] & (1<<4))
+                       x = ~(-x) - 255;
+
+               /* input driver wants -y */
+               if (buffer[1] & (1<<5))
+                       y = -(~(-y) - 255);
+               else
+                       y = -y;
+
+               input_report_key(hid->mouse,
+                                BTN_LEFT, buffer[1] & (1<<0));
+               input_report_key(hid->mouse,
+                                BTN_RIGHT, buffer[1] & (1<<1));
+               input_report_key(hid->mouse,
+                                BTN_MIDDLE, buffer[1] & (1<<2));
+               input_report_rel(hid->mouse, REL_X, x);
+               input_report_rel(hid->mouse, REL_Y, y);
+       } else {
+               /* REVISIT: Does this work? */
+               /* absolute pointing device report */
+               x = buffer[2] + ((buffer[1] & X_MSB_MASK) << X_MSB_SHIFT);
+               y = buffer[3] + ((buffer[1] & Y_MSB_MASK) << Y_MSB_SHIFT);
+               btn = buffer[1] & (1<<0);
+
+               if ((prev_x == x) && (prev_y == y)
+                   && (prev_btn == btn))
+                       return;
+
+               input_report_key(hid->mouse, BTN_LEFT, btn);
+               input_report_abs(hid->mouse, ABS_X, x);
+               input_report_abs(hid->mouse, ABS_Y, y);
+               prev_x = x;
+               prev_y = y;
+               prev_btn = btn;
+       }
+       input_sync(hid->mouse);
+       dbg("HID X: %d Y: %d Functions: %x\n", x, y, buffer[1]);
+}
+
+/*
+ * Reference [1], Appendix A, Semtech standard PS/2 key number definitions,
+ * pgs. A-1 through A-3. The following table lists standard PS/2 key numbers
+ * used by the Juno® 01 keyboard manager.
+ *
+ * NOTES:
+ * 1. The following table indices are E0 codes which require special handling:
+ *     53..62, 77..78, 94, 96, 100, 102..104, 108..110
+ * 2. The following table indices are E1 codes which require special handling:
+ *     101
+ */
+
+static unsigned char usar2scancode[128] = {
+       0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x2b, 0x1e, 0x1f, 0x20,
+       0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+       0x1c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32,
+       0x33, 0x34, 0x35, 0x39, 0x01, 0x52, 0x53, 0x4b,
+       0x47, 0x4f, 0x48, 0x50, 0x49, 0x51, 0x4d, 0x37,
+       0x4e, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47,
+       0x48, 0x49, 0x52, 0x53, 0x4a, 0x1c, 0x35, 0x3b,
+       0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,
+       0x44, 0x57, 0x58, 0x2a, 0x36, 0x38, 0x38, 0x1d,
+       0x1d, 0x3a, 0x45, 0x46, 0x2a, 0x1d, 0x5b, 0x5c,
+       0x5d, 0xff, 0x00, 0x00, 0x5e, 0x5f, 0x63, 0x70,
+       0x7b, 0x79, 0x7d, 0x73, 0x5b, 0x5c, 0x5d, 0x63,
+       0x65, 0x66, 0x68, 0x69, 0x6b, 0x56, 0x54, 0x00
+};
+
+/*
+ * The following are bit masks used to encode E0 scan codes which
+ * require special handling. However, scan codes 100 and 101 are
+ * excludable here since they each require unique multi-byte scan
+ * code translations and are therefore dealt with individually via
+ * handle_print_scr() and handle_pause() respectively below.
+ */
+
+static unsigned long int e0_codes1 = 0x030003ff; /* scan codes 53..84 */
+static unsigned long int e0_codes2 = 0x038e0a00; /* scan codes 85..116 */
+
+static void
+handle_print_scr(int up)
+{
+       if (up) {
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xb7, 1);
+               input_report_key(hid->keyboard, 0xe0, 1);
+               input_report_key(hid->keyboard, 0xaa, 1);
+       } else {
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x2a, 0);
+               input_report_key(hid->keyboard, 0xe0, 0);
+               input_report_key(hid->keyboard, 0x37, 0);
+       }
+}
+
+static void
+handle_pause(void)
+{
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x1d, 0);
+       input_report_key(hid->keyboard, 0x45, 0);
+       input_report_key(hid->keyboard, 0xe1, 0);
+       input_report_key(hid->keyboard, 0x9d, 0);
+       input_report_key(hid->keyboard, 0xc5, 0);
+}
+
+static void
+process_keyboard_report(struct innovator_hid_dev *hid, u8 * buffer)
+{
+       unsigned char ch = buffer[1] & 0x7f;
+       int up = buffer[1] & 0x80 ? 1 : 0;
+       int is_e0 = 0;
+       hid->keyboard = input_allocate_device();
+       hid->mouse = input_allocate_device();
+
+       if ((ch == 106) || (ch == 107))
+               return;         /* no code */
+
+       if (ch == 100) {
+               handle_print_scr(up);
+               return;
+       }
+
+       if (ch == 101) {
+               handle_pause();
+               return;
+       }
+
+       if ((ch >= 53) && (ch <= 84)) {
+               /* first block of e0 codes */
+               is_e0 = e0_codes1 & (1 << (ch - 53));
+       } else if ((ch >= 85) && (ch <= 116)) {
+               /* second block of e0 codes */
+               is_e0 = e0_codes2 & (1 << (ch - 85));
+       }
+
+       if (is_e0) {
+               input_report_key(hid->keyboard, 0xe0, !up);
+       }
+       input_report_key(hid->keyboard, usar2scancode[ch], !up);
+       input_sync(hid->keyboard);
+}
+
+static irqreturn_t
+innovator_hid_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       if (ATN()) {
+               disable_irq(OMAP1510_INT_FPGA_ATN);
+               tasklet_schedule(&hid_tasklet);
+       }
+       return IRQ_HANDLED;
+}
+
+static void
+do_hid_tasklet(unsigned long unused)
+{
+       int ret;
+       if ((ret = report_async(buffer, 256)) == -1) {
+               dbg("Error: Bad Juno return value: %d\n", ret);
+       } else if (ret == KEYBOARD_REPORT) {
+               process_keyboard_report(hid, buffer);
+       } else if (ret == POINTING_REPORT) {
+               process_pointing_report(hid, buffer);
+       } else {
+               dbg("ERROR: bad report\n");
+       }
+       enable_irq(OMAP1510_INT_FPGA_ATN);
+}
+
+static int
+innovator_hid_open(struct input_dev *dev)
+{
+       if (hid->open++)
+               return 0;
+
+       if (request_irq(OMAP1510_INT_FPGA_ATN, (void *) innovator_hid_interrupt,
+                       IRQF_DISABLED, PFX, hid) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void
+innovator_hid_close(struct input_dev *dev)
+{
+       if (!--hid->open)
+               return;
+
+       if (hid == NULL)
+               return;
+
+       kfree(hid);
+}
+
+static int innovator_ps2_remove(struct device *dev)
+{
+       return 0;
+}
+
+static void innovator_ps2_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+
+static int innovator_ps2_suspend(struct device *dev, pm_message_t state)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Set SUS_STATE in REG_PM_COMM (Page 0 R0).  This will cause
+        * PM_MOD bits of REG_PM_STATUS to show suspended state,
+        * but the SUS_STAT bit of REG_PM_STATUS will continue to
+        * reflect the state of the _HSUS pin.
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 suspend: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 suspend: read_reg REG_PM_COMM error\n");
+               
+       if (write_reg(REG_PM_COMM, pmcomm | SUS_STATE) < 0)
+               printk("ps2 suspend: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static int innovator_ps2_resume(struct device *dev)
+{
+       u8 pmcomm = 0;
+
+       /*
+        * Clear SUS_STATE from REG_PM_COMM (Page 0 R0).
+        */
+
+       if (write_reg(REG_PAGENO, 0) < 0)
+               printk("ps2 resume: write_reg REG_PAGENO error\n");
+
+       if (read_reg(REG_PM_COMM, &pmcomm) < 0)
+               printk("ps2 resume: read_reg REG_PM_COMM error\n");
+
+       if (write_reg(REG_PM_COMM, pmcomm & ~SUS_STATE) < 0)
+               printk("ps2 resume: write_reg REG_PM_COMM error\n");
+
+       return 0;
+}
+
+static struct device_driver innovator_ps2_driver = {
+       .name           = "innovator_ps2",
+       .bus            = &platform_bus_type,
+       .remove         = innovator_ps2_remove,
+       .suspend        = innovator_ps2_suspend,
+       .resume         = innovator_ps2_resume,
+};
+
+static struct platform_device innovator_ps2_device = {
+       .name           = "ps2",
+       .id             = -1,
+       .dev = {
+               .driver         = &innovator_ps2_driver,
+               .release        = innovator_ps2_device_release,
+       },
+};
+
+static int __init
+innovator_kbd_init(void)
+{
+       int i;
+       info("Innovator PS/2 keyboard/mouse driver v1.0\n");
+
+       innovator_fpga_hid_reset();
+
+       if ((hid = kmalloc(sizeof(struct innovator_hid_dev),
+            GFP_KERNEL)) == NULL) {
+               warn("unable to allocate space for HID device\n");
+               return -ENOMEM;
+       }
+
+       /* setup the mouse */
+       memset(hid, 0, sizeof(struct innovator_hid_dev));
+       hid->mouse = input_allocate_device();
+       hid->mouse->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+       hid->mouse->keybit[BIT_WORD(BTN_MOUSE)] =
+           BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+           BIT(BTN_MIDDLE) | BIT(BTN_TOUCH);
+       hid->mouse->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+       hid->mouse->private = hid;
+       hid->mouse->open = innovator_hid_open;
+       hid->mouse->close = innovator_hid_close;
+       hid->mouse->name = "innovator_mouse";
+       hid->mouse->id.bustype = 0;
+       hid->mouse->id.vendor = 0;
+       hid->mouse->id.product = 0;
+       hid->mouse->id.version = 0;
+       hid->keyboard = input_allocate_device();
+       hid->keyboard->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+       hid->keyboard->keycodesize = sizeof(unsigned char);
+       hid->keyboard->keycodemax = ARRAY_SIZE(usar2scancode);
+       for(i = 0; i < 128; i++)
+               set_bit(usar2scancode[i], hid->keyboard->keybit);
+       hid->keyboard->private = hid;
+       hid->keyboard->open = innovator_hid_open;
+       hid->keyboard->close = innovator_hid_close;
+       hid->keyboard->name = "innovator_keyboard";
+       hid->keyboard->id.bustype = 0;
+       hid->keyboard->id.vendor = 0;
+       hid->keyboard->id.product = 0;
+       hid->keyboard->id.version = 0;
+       input_register_device(hid->mouse);
+       input_register_device(hid->keyboard);
+       innovator_hid_open(hid->mouse);
+       innovator_hid_open(hid->keyboard);
+
+       if (driver_register(&innovator_ps2_driver) != 0)
+               printk(KERN_ERR "Driver register failed for innovator_ps2\n");
+
+       if (platform_device_register(&innovator_ps2_device) != 0) {
+               printk(KERN_ERR "Device register failed for ps2\n");
+               driver_unregister(&innovator_ps2_driver);
+       }
+
+#ifdef INNOVATOR_KEYB_DEBUG
+       ctrl_dump_regs();
+#endif
+       return 0;
+}
+
+static void __exit
+innovator_kbd_exit(void)
+{
+       input_unregister_device(hid->mouse);
+       input_unregister_device(hid->keyboard);
+       free_irq(OMAP1510_INT_FPGA_ATN, hid);
+       if (hid != NULL)
+               kfree(hid);
+       driver_unregister(&innovator_ps2_driver);
+       platform_device_unregister(&innovator_ps2_device);
+       return;
+}
+
+module_init(innovator_kbd_init);
+module_exit(innovator_kbd_exit);
+
+MODULE_AUTHOR("George G. Davis <gdavis@mvista.com>");
+MODULE_DESCRIPTION("Innovator PS/2 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
new file mode 100644 (file)
index 0000000..72bb587
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * drivers/i2c/chips/lm8323.c
+ *
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * Written by Daniel Stone <daniel.stone@nokia.com>
+ *            Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License only).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/i2c/lm8323.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#ifdef VERBOSE
+#define debug dev_dbg
+#else
+#define debug(...)
+#endif
+
+/* Commands to send to the chip. */
+#define LM8323_CMD_READ_ID             0x80 /* Read chip ID. */
+#define LM8323_CMD_WRITE_CFG           0x81 /* Set configuration item. */
+#define LM8323_CMD_READ_INT            0x82 /* Get interrupt status. */
+#define LM8323_CMD_RESET               0x83 /* Reset, same as external one */
+#define LM8323_CMD_WRITE_PORT_SEL      0x85 /* Set GPIO in/out. */
+#define LM8323_CMD_WRITE_PORT_STATE    0x86 /* Set GPIO pullup. */
+#define LM8323_CMD_READ_PORT_SEL       0x87 /* Get GPIO in/out. */
+#define LM8323_CMD_READ_PORT_STATE     0x88 /* Get GPIO pullup. */
+#define LM8323_CMD_READ_FIFO           0x89 /* Read byte from FIFO. */
+#define LM8323_CMD_RPT_READ_FIFO       0x8a /* Read FIFO (no increment). */
+#define LM8323_CMD_SET_ACTIVE          0x8b /* Set active time. */
+#define LM8323_CMD_READ_ERR            0x8c /* Get error status. */
+#define LM8323_CMD_READ_ROTATOR                0x8e /* Read rotator status. */
+#define LM8323_CMD_SET_DEBOUNCE                0x8f /* Set debouncing time. */
+#define LM8323_CMD_SET_KEY_SIZE                0x90 /* Set keypad size. */
+#define LM8323_CMD_READ_KEY_SIZE       0x91 /* Get keypad size. */
+#define LM8323_CMD_READ_CFG            0x92 /* Get configuration item. */
+#define LM8323_CMD_WRITE_CLOCK         0x93 /* Set clock config. */
+#define LM8323_CMD_READ_CLOCK          0x94 /* Get clock config. */
+#define LM8323_CMD_PWM_WRITE           0x95 /* Write PWM script. */
+#define LM8323_CMD_START_PWM           0x96 /* Start PWM engine. */
+#define LM8323_CMD_STOP_PWM            0x97 /* Stop PWM engine. */
+
+/* Interrupt status. */
+#define INT_KEYPAD                     0x01 /* Key event. */
+#define INT_ROTATOR                    0x02 /* Rotator event. */
+#define INT_ERROR                      0x08 /* Error: use CMD_READ_ERR. */
+#define INT_NOINIT                     0x10 /* Lost configuration. */
+#define INT_PWM1                       0x20 /* PWM1 stopped. */
+#define INT_PWM2                       0x40 /* PWM2 stopped. */
+#define INT_PWM3                       0x80 /* PWM3 stopped. */
+
+/* Errors (signalled by INT_ERROR, read with CMD_READ_ERR). */
+#define ERR_BADPAR                     0x01 /* Bad parameter. */
+#define ERR_CMDUNK                     0x02 /* Unknown command. */
+#define ERR_KEYOVR                     0x04 /* Too many keys pressed. */
+#define ERR_FIFOOVER                   0x40 /* FIFO overflow. */
+
+/* Configuration keys (CMD_{WRITE,READ}_CFG). */
+#define CFG_MUX1SEL                    0x01 /* Select MUX1_OUT input. */
+#define CFG_MUX1EN                     0x02 /* Enable MUX1_OUT. */
+#define CFG_MUX2SEL                    0x04 /* Select MUX2_OUT input. */
+#define CFG_MUX2EN                     0x08 /* Enable MUX2_OUT. */
+#define CFG_PSIZE                      0x20 /* Package size (must be 0). */
+#define CFG_ROTEN                      0x40 /* Enable rotator. */
+
+/* Clock settings (CMD_{WRITE,READ}_CLOCK). */
+#define CLK_RCPWM_INTERNAL             0x00
+#define CLK_RCPWM_EXTERNAL             0x03
+#define CLK_SLOWCLKEN                  0x08 /* Enable 32.768kHz clock. */
+#define CLK_SLOWCLKOUT                 0x40 /* Enable slow pulse output. */
+
+/* The possible addresses corresponding to CONFIG1 and CONFIG2 pin wirings. */
+#define LM8323_I2C_ADDR00              (0x84 >> 1)     /* 1000 010x */
+#define LM8323_I2C_ADDR01              (0x86 >> 1)     /* 1000 011x */
+#define LM8323_I2C_ADDR10              (0x88 >> 1)     /* 1000 100x */
+#define LM8323_I2C_ADDR11              (0x8A >> 1)     /* 1000 101x */
+
+/* Key event fifo length */
+#define LM8323_FIFO_LEN                        15
+
+/* Commands for PWM engine; feed in with PWM_WRITE. */
+/* Load ramp counter from duty cycle field (range 0 - 0xff). */
+#define PWM_SET(v)                     (0x4000 | ((v) & 0xff))
+/* Go to start of script. */
+#define PWM_GOTOSTART                  0x0000
+/*
+ * Stop engine (generates interrupt).  If reset is 1, clear the program
+ * counter, else leave it.
+ */
+#define PWM_END(reset)                 (0xc000 | (!!(reset) << 11))
+/*
+ * Ramp.  If s is 1, divide clock by 512, else divide clock by 16.
+ * Take t clock scales (up to 63) per step, for n steps (up to 126).
+ * If u is set, ramp up, else ramp down.
+ */
+#define PWM_RAMP(s, t, n, u)           ((!!(s) << 14) | ((t) & 0x3f) << 8 | \
+                                        ((n) & 0x7f) | ((u) ? 0 : 0x80))
+/*
+ * Loop (i.e. jump back to pos) for a given number of iterations (up to 63).
+ * If cnt is zero, execute until PWM_END is encountered.
+ */
+#define PWM_LOOP(cnt, pos)             (0xa000 | (((cnt) & 0x3f) << 7) | \
+                                        ((pos) & 0x3f))
+/*
+ * Wait for trigger.  Argument is a mask of channels, shifted by the channel
+ * number, e.g. 0xa for channels 3 and 1.  Note that channels are numbered
+ * from 1, not 0.
+ */
+#define PWM_WAIT_TRIG(chans)           (0xe000 | (((chans) & 0x7) << 6))
+/* Send trigger.  Argument is same as PWM_WAIT_TRIG. */
+#define PWM_SEND_TRIG(chans)           (0xe000 | ((chans) & 0x7))
+
+#define DRIVER_NAME  "lm8323"
+
+struct lm8323_pwm {
+       int                     id;
+       int                     enabled;
+       int                     fade_time;
+       int                     brightness;
+       int                     desired_brightness;
+       struct work_struct      work;
+       struct led_classdev     cdev;
+};
+
+struct lm8323_chip {
+       struct mutex            lock;
+       struct i2c_client       *client;
+       struct work_struct      work;
+       struct input_dev        *idev;
+       unsigned                kp_enabled : 1;
+       unsigned                pm_suspend : 1;
+       unsigned                keys_down;
+       char                    phys[32];
+       s16                     keymap[LM8323_KEYMAP_SIZE];
+       int                     size_x;
+       int                     size_y;
+       int                     debounce_time;
+       int                     active_time;
+       struct lm8323_pwm       pwm1;
+       struct lm8323_pwm       pwm2;
+       struct lm8323_pwm       pwm3;
+};
+
+#define client_to_lm8323(c)    container_of(c, struct lm8323_chip, client)
+#define dev_to_lm8323(d)       container_of(d, struct lm8323_chip, client->dev)
+#define work_to_lm8323(w)      container_of(w, struct lm8323_chip, work)
+#define cdev_to_pwm(c)         container_of(c, struct lm8323_pwm, cdev)
+#define work_to_pwm(w)         container_of(w, struct lm8323_pwm, work)
+
+static struct lm8323_chip *pwm_to_lm8323(struct lm8323_pwm *pwm)
+{
+       switch (pwm->id) {
+       case 1:
+               return container_of(pwm, struct lm8323_chip, pwm1);
+       case 2:
+               return container_of(pwm, struct lm8323_chip, pwm2);
+       case 3:
+               return container_of(pwm, struct lm8323_chip, pwm3);
+       default:
+               return NULL;
+       }
+}
+
+static struct lm8323_platform_data *lm8323_pdata;
+
+
+#define LM8323_MAX_DATA 8
+
+/*
+ * To write, we just access the chip's address in write mode, and dump the
+ * command and data out on the bus.  The command byte and data are taken as
+ * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA.
+ */
+static int lm8323_write(struct lm8323_chip *lm, int len, ...)
+{
+       int ret, i;
+       va_list ap;
+       u8 data[LM8323_MAX_DATA];
+
+       va_start(ap, len);
+
+       if (unlikely(len > LM8323_MAX_DATA)) {
+               dev_err(&lm->client->dev, "tried to send %d bytes\n", len);
+               va_end(ap);
+               return 0;
+       }
+
+       for (i = 0; i < len; i++)
+               data[i] = va_arg(ap, int);
+
+       va_end(ap);
+
+       /*
+        * If the host is asleep while we send the data, we can get a NACK
+        * back while it wakes up, so try again, once.
+        */
+       ret = i2c_master_send(lm->client, data, len);
+       if (unlikely(ret == -EREMOTEIO))
+               ret = i2c_master_send(lm->client, data, len);
+       if (unlikely(ret != len))
+               dev_err(&lm->client->dev, "sent %d bytes of %d total\n",
+                       len, ret);
+
+       return ret;
+}
+
+/*
+ * To read, we first send the command byte to the chip and end the transaction,
+ * then access the chip in read mode, at which point it will send the data.
+ */
+static int lm8323_read(struct lm8323_chip *lm, u8 cmd, u8 *buf, int len)
+{
+       int ret;
+
+       /*
+        * If the host is asleep while we send the byte, we can get a NACK
+        * back while it wakes up, so try again, once.
+        */
+       ret = i2c_master_send(lm->client, &cmd, 1);
+       if (unlikely(ret == -EREMOTEIO))
+               ret = i2c_master_send(lm->client, &cmd, 1);
+       if (unlikely(ret != 1)) {
+               dev_err(&lm->client->dev, "sending read cmd 0x%02x failed\n",
+                       cmd);
+               return 0;
+       }
+
+       ret = i2c_master_recv(lm->client, buf, len);
+       if (unlikely(ret != len))
+               dev_err(&lm->client->dev, "wanted %d bytes, got %d\n",
+                       len, ret);
+
+       return ret;
+}
+
+/*
+ * Set the chip active time (idle time before it enters halt).
+ */
+static void lm8323_set_active_time(struct lm8323_chip *lm, int time)
+{
+       lm8323_write(lm, 2, LM8323_CMD_SET_ACTIVE, time >> 2);
+}
+
+/*
+ * The signals are AT-style: the low 7 bits are the keycode, and the top
+ * bit indicates the state (1 for down, 0 for up).
+ */
+static inline u8 lm8323_whichkey(u8 event)
+{
+       return event & 0x7f;
+}
+
+static inline int lm8323_ispress(u8 event)
+{
+       return (event & 0x80) ? 1 : 0;
+}
+
+static void process_keys(struct lm8323_chip *lm)
+{
+       u8 event;
+       u8 key_fifo[LM8323_FIFO_LEN + 1];
+       int old_keys_down = lm->keys_down;
+       int ret;
+       int i = 0;
+
+       /*
+        * Read all key events from the FIFO at once. Next READ_FIFO clears the
+        * FIFO even if we didn't read all events previously.
+        */
+       ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN);
+
+       if (ret < 0) {
+               dev_err(&lm->client->dev, "Failed reading fifo \n");
+               return;
+       }
+       key_fifo[ret] = 0;
+
+       while ((event = key_fifo[i])) {
+               u8 key = lm8323_whichkey(event);
+               int isdown = lm8323_ispress(event);
+               s16 keycode = lm->keymap[key];
+
+               if (likely(keycode > 0)) {
+                       debug(&lm->client->dev, "key 0x%02x %s\n", key,
+                             isdown ? "down" : "up");
+                       if (likely(lm->kp_enabled)) {
+                               input_report_key(lm->idev, keycode, isdown);
+                               input_sync(lm->idev);
+                       }
+                       if (isdown)
+                               lm->keys_down++;
+                       else
+                               lm->keys_down--;
+               } else {
+                       dev_err(&lm->client->dev, "keycode 0x%02x not mapped "
+                               "to any key\n", key);
+               }
+               i++;
+       }
+
+       /*
+        * Errata: We need to ensure that the chip never enters halt mode
+        * during a keypress, so set active time to 0.  When it's released,
+        * we can enter halt again, so set the active time back to normal.
+        */
+       if (!old_keys_down && lm->keys_down)
+               lm8323_set_active_time(lm, 0);
+       if (old_keys_down && !lm->keys_down)
+               lm8323_set_active_time(lm, lm->active_time);
+}
+
+static void lm8323_process_error(struct lm8323_chip *lm)
+{
+       u8 error;
+
+       if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) {
+               if (error & ERR_FIFOOVER)
+                       debug(&lm->client->dev, "fifo overflow!\n");
+               if (error & ERR_KEYOVR)
+                       debug(&lm->client->dev, "more than two keys pressed\n");
+               if (error & ERR_CMDUNK)
+                       debug(&lm->client->dev, "unknown command submitted\n");
+               if (error & ERR_BADPAR)
+                       debug(&lm->client->dev, "bad command parameter\n");
+       }
+}
+
+static void lm8323_reset(struct lm8323_chip *lm)
+{
+       /* The docs say we must pass 0xAA as the data byte. */
+       lm8323_write(lm, 2, LM8323_CMD_RESET, 0xAA);
+}
+
+static int lm8323_configure(struct lm8323_chip *lm)
+{
+       int keysize = (lm->size_x << 4) | lm->size_y;
+       int clock = (CLK_SLOWCLKEN | CLK_RCPWM_EXTERNAL);
+       int debounce = lm->debounce_time >> 2;
+       int active = lm->active_time >> 2;
+
+       /*
+        * Active time must be greater than the debounce time: if it's
+        * a close-run thing, give ourselves a 12ms buffer.
+        */
+       if (debounce >= active)
+               active = debounce + 3;
+
+       lm8323_write(lm, 2, LM8323_CMD_WRITE_CFG, 0);
+       lm8323_write(lm, 2, LM8323_CMD_WRITE_CLOCK, clock);
+       lm8323_write(lm, 2, LM8323_CMD_SET_KEY_SIZE, keysize);
+       lm8323_set_active_time(lm, lm->active_time);
+       lm8323_write(lm, 2, LM8323_CMD_SET_DEBOUNCE, debounce);
+       lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_STATE, 0xff, 0xff);
+       lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_SEL, 0, 0);
+
+       /*
+        * Not much we can do about errors at this point, so just hope
+        * for the best.
+        */
+
+       return 0;
+}
+
+/*
+ * Bottom half: handle the interrupt by posting key events, or dealing with
+ * errors appropriately.
+ */
+static void lm8323_work(struct work_struct *work)
+{
+       struct lm8323_chip *lm = work_to_lm8323(work);
+       u8 ints;
+
+       mutex_lock(&lm->lock);
+
+       while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) {
+               if (likely(ints & INT_KEYPAD))
+                       process_keys(lm);
+               if (ints & INT_ROTATOR) {
+                       /* We don't currently support the rotator. */
+                       debug(&lm->client->dev, "rotator fired\n");
+               }
+               if (ints & INT_ERROR) {
+                       debug(&lm->client->dev, "error!\n");
+                       lm8323_process_error(lm);
+               }
+               if (ints & INT_NOINIT) {
+                       dev_err(&lm->client->dev, "chip lost config; "
+                                                 "reinitialising\n");
+                       lm8323_configure(lm);
+               }
+               if (ints & INT_PWM1)
+                       debug(&lm->client->dev, "pwm1 engine completed\n");
+               if (ints & INT_PWM2)
+                       debug(&lm->client->dev, "pwm2 engine completed\n");
+               if (ints & INT_PWM3)
+                       debug(&lm->client->dev, "pwm3 engine completed\n");
+       }
+
+       mutex_unlock(&lm->lock);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t lm8323_irq(int irq, void *data)
+{
+       struct lm8323_chip *lm = data;
+
+       schedule_work(&lm->work);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Read the chip ID.
+ */
+static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf)
+{
+       int bytes;
+
+       bytes = lm8323_read(lm, LM8323_CMD_READ_ID, buf, 2);
+       if (unlikely(bytes != 2))
+               return -EIO;
+
+       return 0;
+}
+
+static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd)
+{
+       struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+
+       lm8323_write(lm, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id,
+                    (cmd & 0xff00) >> 8, cmd & 0x00ff);
+}
+
+/*
+ * Write a script into a given PWM engine, concluding with PWM_END.
+ * If 'keepalive' is specified, the engine will be kept running
+ * indefinitely.
+ */
+static void lm8323_write_pwm(struct lm8323_pwm *pwm, int keepalive,
+                            int len, ...)
+{
+       struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+       int i, cmd;
+       va_list ap;
+
+       /*
+        * If there are any scripts running at the moment, terminate them
+        * and make sure the duty cycle is as if it finished.
+        */
+       lm8323_write(lm, 2, LM8323_CMD_STOP_PWM, pwm->id);
+
+       va_start(ap, len);
+       for (i = 0; i < len; i++) {
+               cmd = va_arg(ap, int);
+               lm8323_write_pwm_one(pwm, i, cmd);
+       }
+       va_end(ap);
+
+       /* Wait for a trigger from any channel. This keeps the engine alive. */
+       if (keepalive)
+               lm8323_write_pwm_one(pwm, i++, PWM_WAIT_TRIG(0xe));
+       else
+               lm8323_write_pwm_one(pwm, i++, PWM_END(1));
+
+       lm8323_write(lm, 2, LM8323_CMD_START_PWM, pwm->id);
+}
+
+static void lm8323_pwm_work(struct work_struct *work)
+{
+       struct lm8323_pwm *pwm = work_to_pwm(work);
+       int div, perstep, steps, hz, direction, keepalive;
+
+       /* Do nothing if we're already at the requested level. */
+       if (pwm->desired_brightness == pwm->brightness)
+               return;
+
+       keepalive = (pwm->desired_brightness > 0);
+       direction = (pwm->desired_brightness > pwm->brightness);
+       steps = abs(pwm->desired_brightness - pwm->brightness);
+
+       /*
+        * Convert time (in ms) into a divisor (512 or 16 on a refclk of
+        * 32768Hz), and number of ticks per step.
+        */
+       if ((pwm->fade_time / steps) > (32768 / 512))
+               div = 512;
+       else
+               div = 16;
+
+       hz = 32768 / div;
+       if (pwm->fade_time < ((steps * 1000) / hz))
+               perstep = 1;
+       else
+               perstep = (hz * pwm->fade_time) / (steps * 1000);
+
+       if (perstep == 0)
+               perstep = 1;
+       else if (perstep > 63)
+               perstep = 63;
+
+       if (steps > 252) {
+               lm8323_write_pwm(pwm, keepalive, 3,
+                                PWM_RAMP((div == 512), perstep, 126,
+                                         direction),
+                                PWM_RAMP((div == 512), perstep, 126,
+                                         direction),
+                                PWM_RAMP((div == 512), perstep, steps - 252,
+                                         direction));
+       } else if (steps > 126) {
+               lm8323_write_pwm(pwm, keepalive, 2,
+                                PWM_RAMP((div == 512), perstep, 126,
+                                         direction),
+                                PWM_RAMP((div == 512), perstep, steps - 126,
+                                         direction));
+       } else {
+               lm8323_write_pwm(pwm, keepalive, 1,
+                                PWM_RAMP((div == 512), perstep, steps,
+                                         direction));
+       }
+
+       pwm->brightness = pwm->desired_brightness;
+}
+
+static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
+                                     enum led_brightness brightness)
+{
+       struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+       struct lm8323_chip *lm = pwm_to_lm8323(pwm);
+
+       pwm->desired_brightness = brightness;
+
+       if (in_interrupt()) {
+               schedule_work(&pwm->work);
+       } else {
+               /*
+                * Schedule PWM work as usual unless we are going into suspend
+                */
+               mutex_lock(&lm->lock);
+               if (likely(!lm->pm_suspend))
+                       schedule_work(&pwm->work);
+               else
+                       lm8323_pwm_work(&pwm->work);
+               mutex_unlock(&lm->lock);
+       }
+}
+
+static ssize_t lm8323_pwm_show_time(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+
+       return sprintf(buf, "%d\n", pwm->fade_time);
+}
+
+static ssize_t lm8323_pwm_store_time(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+       int ret;
+       int time;
+
+       ret = sscanf(buf, "%d", &time);
+       /* Numbers only, please. */
+       if (ret)
+               return -EINVAL;
+
+       pwm->fade_time = time;
+
+       return strlen(buf);
+}
+static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time);
+
+static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
+                   const char *name)
+{
+       struct lm8323_pwm *pwm = NULL;
+
+       BUG_ON(id > 3);
+
+       switch (id) {
+       case 1:
+               pwm = &lm->pwm1;
+               break;
+       case 2:
+               pwm = &lm->pwm2;
+               break;
+       case 3:
+               pwm = &lm->pwm3;
+               break;
+       }
+
+       pwm->id = id;
+       pwm->fade_time = 0;
+       pwm->brightness = 0;
+       pwm->desired_brightness = 0;
+       if (name) {
+               pwm->cdev.name = name;
+               pwm->cdev.brightness_set = lm8323_pwm_set_brightness;
+               if (led_classdev_register(dev, &pwm->cdev) < 0) {
+                       dev_err(dev, "couldn't register PWM %d\n", id);
+                       return -1;
+               }
+               if (device_create_file(pwm->cdev.dev,
+                                            &dev_attr_time) < 0) {
+                       dev_err(dev, "couldn't register time attribute\n");
+                       led_classdev_unregister(&pwm->cdev);
+                       return -1;
+               }
+               INIT_WORK(&pwm->work, lm8323_pwm_work);
+               pwm->enabled = 1;
+       } else {
+               pwm->enabled = 0;
+       }
+
+       return 0;
+}
+
+static struct i2c_driver lm8323_i2c_driver;
+
+static ssize_t lm8323_show_disable(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct lm8323_chip *lm = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", !lm->kp_enabled);
+}
+
+static ssize_t lm8323_set_disable(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct lm8323_chip *lm = dev_get_drvdata(dev);
+       int ret;
+       int i;
+
+       i = sscanf(buf, "%d", &ret);
+
+       mutex_lock(&lm->lock);
+       lm->kp_enabled = !i;
+       mutex_unlock(&lm->lock);
+
+       return count;
+}
+static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
+
+static int lm8323_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct input_dev *idev;
+       struct lm8323_chip *lm;
+       int i, err = 0;
+       unsigned long tmo;
+       u8 data[2];
+
+       lm = kzalloc(sizeof *lm, GFP_KERNEL);
+       if (!lm)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, lm);
+       lm->client = client;
+       lm8323_pdata = client->dev.platform_data;
+       if (!lm8323_pdata)
+               return -EINVAL; /* ? */
+
+       lm->size_x = lm8323_pdata->size_x;
+       if (lm->size_x == 0) {
+               lm->size_x = 8;
+       } else if (lm->size_x > 8) {
+               dev_err(&client->dev, "invalid x size %d specified\n",
+                               lm->size_x);
+               lm->size_x = 8;
+       }
+
+       lm->size_y = lm8323_pdata->size_y;
+       if (lm->size_y == 0) {
+               lm->size_y = 12;
+       } else if (lm->size_y > 12) {
+               dev_err(&client->dev, "invalid y size %d specified\n",
+                               lm->size_y);
+               lm->size_x = 12;
+       }
+
+       debug(&c->dev, "Keypad size: %d x %d\n", lm->size_x, lm->size_y);
+
+       lm->debounce_time = lm8323_pdata->debounce_time;
+       if (lm->debounce_time == 0) /* Default. */
+               lm->debounce_time = 12;
+       else if (lm->debounce_time == -1) /* Disable debounce. */
+               lm->debounce_time = 0;
+
+       lm->active_time = lm8323_pdata->active_time;
+       if (lm->active_time == 0) /* Default. */
+               lm->active_time = 500;
+       else if (lm->active_time == -1) /* Disable sleep. */
+               lm->active_time = 0;
+
+       lm8323_reset(lm);
+
+       /* Nothing's set up to service the IRQ yet, so just spin for max.
+        * 100ms until we can configure. */
+       tmo = jiffies + msecs_to_jiffies(100);
+       while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) {
+               if (data[0] & INT_NOINIT)
+                       break;
+
+               if (time_after(jiffies, tmo)) {
+                       dev_err(&client->dev,
+                                       "timeout waiting for initialisation\n");
+                       break;
+               }
+
+               msleep(1);
+       }
+       lm8323_configure(lm);
+
+       /* If a true probe check the device */
+       if (lm8323_read_id(lm, data) != 0) {
+               dev_err(&client->dev, "device not found\n");
+               err = -ENODEV;
+               goto fail2;
+       }
+
+       if (init_pwm(lm, 1, &client->dev, lm8323_pdata->pwm1_name) < 0)
+               goto fail3;
+       if (init_pwm(lm, 2, &client->dev, lm8323_pdata->pwm2_name) < 0)
+               goto fail4;
+       if (init_pwm(lm, 3, &client->dev, lm8323_pdata->pwm3_name) < 0)
+               goto fail5;
+
+       mutex_init(&lm->lock);
+       INIT_WORK(&lm->work, lm8323_work);
+
+       err = request_irq(client->irq, lm8323_irq,
+                         IRQF_TRIGGER_FALLING | IRQF_DISABLED |
+                         IRQF_SAMPLE_RANDOM, DRIVER_NAME, lm);
+       if (err) {
+               dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
+               goto fail6;
+       }
+
+       set_irq_wake(client->irq, 1);
+
+       lm->kp_enabled = 1;
+       err = device_create_file(&client->dev, &dev_attr_disable_kp);
+       if (err < 0)
+               goto fail7;
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               err = -ENOMEM;
+               goto fail8;
+       }
+
+       if (lm8323_pdata->name)
+               idev->name = lm8323_pdata->name;
+       else
+               idev->name = "LM8323 keypad";
+       snprintf(lm->phys, sizeof(lm->phys), "%s/input-kp", client->dev.bus_id);
+       idev->phys = lm->phys;
+
+       lm->keys_down = 0;
+       idev->evbit[0] = BIT(EV_KEY);
+       for (i = 0; i < LM8323_KEYMAP_SIZE; i++) {
+               if (lm8323_pdata->keymap[i] > 0)
+                       set_bit(lm8323_pdata->keymap[i], idev->keybit);
+
+               lm->keymap[i] = lm8323_pdata->keymap[i];
+       }
+
+       if (lm8323_pdata->repeat)
+               set_bit(EV_REP, idev->evbit);
+
+       lm->idev = idev;
+       err = input_register_device(idev);
+       if (err) {
+               dev_dbg(&client->dev, "error registering input device\n");
+               goto fail8;
+       }
+
+       return 0;
+
+fail8:
+       device_remove_file(&client->dev, &dev_attr_disable_kp);
+fail7:
+       free_irq(client->irq, lm);
+fail6:
+       if (lm->pwm3.enabled)
+               led_classdev_unregister(&lm->pwm3.cdev);
+fail5:
+       if (lm->pwm2.enabled)
+               led_classdev_unregister(&lm->pwm2.cdev);
+fail4:
+       if (lm->pwm1.enabled)
+               led_classdev_unregister(&lm->pwm1.cdev);
+fail3:
+fail2:
+       kfree(lm);
+       return err;
+}
+
+static int lm8323_remove(struct i2c_client *client)
+{
+       struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+       free_irq(client->irq, lm);
+       cancel_work_sync(&lm->work);
+       input_unregister_device(lm->idev);
+       device_remove_file(&lm->client->dev, &dev_attr_disable_kp);
+       if (lm->pwm3.enabled)
+               led_classdev_unregister(&lm->pwm3.cdev);
+       if (lm->pwm2.enabled)
+               led_classdev_unregister(&lm->pwm2.cdev);
+       if (lm->pwm1.enabled)
+               led_classdev_unregister(&lm->pwm1.cdev);
+       kfree(lm);
+
+       return 0;
+}
+
+/*
+ * We don't need to explicitly suspend the chip, as it already switches off
+ * when there's no activity.
+ */
+static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+       set_irq_wake(client->irq, 0);
+       disable_irq(client->irq);
+
+       mutex_lock(&lm->lock);
+       lm->pm_suspend = 1;
+       mutex_unlock(&lm->lock);
+
+       if (lm->pwm1.enabled)
+               led_classdev_suspend(&lm->pwm1.cdev);
+       if (lm->pwm2.enabled)
+               led_classdev_suspend(&lm->pwm2.cdev);
+       if (lm->pwm3.enabled)
+               led_classdev_suspend(&lm->pwm3.cdev);
+
+       return 0;
+}
+
+static int lm8323_resume(struct i2c_client *client)
+{
+       struct lm8323_chip *lm = i2c_get_clientdata(client);
+
+       mutex_lock(&lm->lock);
+       lm->pm_suspend = 0;
+       mutex_unlock(&lm->lock);
+
+       if (lm->pwm1.enabled)
+               led_classdev_resume(&lm->pwm1.cdev);
+       if (lm->pwm2.enabled)
+               led_classdev_resume(&lm->pwm2.cdev);
+       if (lm->pwm3.enabled)
+               led_classdev_resume(&lm->pwm3.cdev);
+
+       enable_irq(client->irq);
+       set_irq_wake(client->irq, 1);
+
+       return 0;
+}
+
+static const struct i2c_device_id lm8323_id[] = {
+       { DRIVER_NAME, 0 },
+       { }
+};
+
+static struct i2c_driver lm8323_i2c_driver = {
+       .driver = {
+               .name    = DRIVER_NAME,
+       },
+       .probe          = lm8323_probe,
+       .remove         = __devexit_p(lm8323_remove),
+       .suspend        = lm8323_suspend,
+       .resume         = lm8323_resume,
+       .id_table       = lm8323_id,
+};
+MODULE_DEVICE_TABLE(i2c, lm8323_id);
+
+static int __init lm8323_init(void)
+{
+       return i2c_add_driver(&lm8323_i2c_driver);
+}
+
+static void __exit lm8323_exit(void)
+{
+       i2c_del_driver(&lm8323_i2c_driver);
+}
+
+MODULE_AUTHOR("Daniel Stone");
+MODULE_DESCRIPTION("LM8323 keypad driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm8323_init);
+module_exit(lm8323_exit);
index dcea87a0bc5674e16b88502273b903d684800663..d57d2cb718fc4867c8c48c5fb9fede04ebc996cc 100644 (file)
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
+#include <linux/i2c/menelaus.h>
 #include <mach/gpio.h>
 #include <mach/keypad.h>
-#include <mach/menelaus.h>
 #include <asm/irq.h>
 #include <mach/hardware.h>
 #include <asm/io.h>
+#include <asm/mach-types.h>
 #include <mach/mux.h>
 
 #undef NEW_BOARD_LEARNING_MODE
@@ -60,9 +62,11 @@ 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);
+static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
 
 static int *keymap;
 static unsigned int *row_gpios;
@@ -72,12 +76,9 @@ static unsigned int *col_gpios;
 static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
 {
        int col;
-       for (col = 0; col < omap_kp->cols; col++) {
-               if (value & (1 << col))
-                       omap_set_gpio_dataout(col_gpios[col], 1);
-               else
-                       omap_set_gpio_dataout(col_gpios[col], 0);
-       }
+
+       for (col = 0; col < omap_kp->cols; col++)
+               gpio_set_value(col_gpios[col], value & (1 << col));
 }
 
 static u8 get_row_gpio_val(struct omap_kp *omap_kp)
@@ -86,7 +87,7 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
        u8 value = 0;
 
        for (row = 0; row < omap_kp->rows; row++) {
-               if (omap_get_gpio_datain(row_gpios[row]))
+               if (gpio_get_value(row_gpios[row]))
                        value |= (1 << row);
        }
        return value;
@@ -99,6 +100,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()) {
@@ -270,15 +279,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
@@ -291,7 +314,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");
@@ -308,7 +331,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())
@@ -333,23 +358,23 @@ static int __init omap_kp_probe(struct platform_device *pdev)
        if (cpu_is_omap24xx()) {
                /* Cols: outputs */
                for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
-                       if (omap_request_gpio(col_gpios[col_idx]) < 0) {
+                       if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
                                printk(KERN_ERR "Failed to request"
                                       "GPIO%d for keypad\n",
                                       col_gpios[col_idx]);
                                goto err1;
                        }
-                       omap_set_gpio_direction(col_gpios[col_idx], 0);
+                       gpio_direction_output(col_gpios[col_idx], 0);
                }
                /* Rows: inputs */
                for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
-                       if (omap_request_gpio(row_gpios[row_idx]) < 0) {
+                       if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
                                printk(KERN_ERR "Failed to request"
                                       "GPIO%d for keypad\n",
                                       row_gpios[row_idx]);
                                goto err2;
                        }
-                       omap_set_gpio_direction(row_gpios[row_idx], 1);
+                       gpio_direction_input(row_gpios[row_idx]);
                }
        } else {
                col_idx = 0;
@@ -418,10 +443,10 @@ err3:
        device_remove_file(&pdev->dev, &dev_attr_enable);
 err2:
        for (i = row_idx - 1; i >=0; i--)
-               omap_free_gpio(row_gpios[i]);
+               gpio_free(row_gpios[i]);
 err1:
        for (i = col_idx - 1; i >=0; i--)
-               omap_free_gpio(col_gpios[i]);
+               gpio_free(col_gpios[i]);
 
        kfree(omap_kp);
        input_free_device(input_dev);
@@ -438,9 +463,9 @@ static int omap_kp_remove(struct platform_device *pdev)
        if (cpu_is_omap24xx()) {
                int i;
                for (i = 0; i < omap_kp->cols; i++)
-                       omap_free_gpio(col_gpios[i]);
+                       gpio_free(col_gpios[i]);
                for (i = 0; i < omap_kp->rows; i++) {
-                       omap_free_gpio(row_gpios[i]);
+                       gpio_free(row_gpios[i]);
                        free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
                }
        } else {
diff --git a/drivers/input/keyboard/omap-twl4030keypad.c b/drivers/input/keyboard/omap-twl4030keypad.c
new file mode 100644 (file)
index 0000000..d3e1d20
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * drivers/input/keyboard/omap-twl4030keypad.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Code re-written for 2430SDP by:
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ * Manjunatha G K <manjugk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/irq.h>
+#include "twl4030-keypad.h"
+
+#define PTV_PRESCALER          4
+
+#define MAX_ROWS               8 /* TWL4030 hardlimit */
+#define ROWCOL_MASK            0xFF000000
+#define KEYNUM_MASK            0x00FFFFFF
+#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
+
+/* Global variables */
+
+struct omap_keypad {
+       int             *keymap;
+       unsigned int    keymapsize;
+       u16             kp_state[MAX_ROWS];
+       int             n_rows;
+       int             n_cols;
+       int             irq;
+
+       struct device   *dbg_dev;
+       struct input_dev *omap_twl4030kp;
+
+       /* sync read/write */
+       struct mutex    mutex;
+};
+
+static int twl4030_kpread(struct omap_keypad *kp,
+               u32 module, u8 *data, u32 reg, u8 num_bytes)
+{
+       int ret;
+
+       ret = twl4030_i2c_read(module, data, reg, num_bytes);
+       if (ret < 0) {
+               dev_warn(kp->dbg_dev,
+                       "Couldn't read TWL4030: %X - ret %d[%x]\n",
+                        reg, ret, ret);
+               return ret;
+       }
+       return ret;
+}
+
+static int twl4030_kpwrite_u8(struct omap_keypad *kp,
+               u32 module, u8 data, u32 reg)
+{
+       int ret;
+
+       ret = twl4030_i2c_write_u8(module, data, reg);
+       if (ret < 0) {
+               dev_warn(kp->dbg_dev,
+                       "Could not write TWL4030: %X - ret %d[%x]\n",
+                        reg, ret, ret);
+               return ret;
+       }
+       return ret;
+}
+
+static int omap_kp_find_key(struct omap_keypad *kp, int col, int row)
+{
+       int i, rc;
+
+       rc = KEY(col, row, 0);
+       for (i = 0; i < kp->keymapsize; i++)
+               if ((kp->keymap[i] & ROWCOL_MASK) == rc)
+                       return kp->keymap[i] & KEYNUM_MASK;
+
+       return -EINVAL;
+}
+
+static inline u16 omap_kp_col_xlate(struct omap_keypad *kp, u8 col)
+{
+       /* If all bits in a row are active for all coloumns then
+        * we have that row line connected to gnd. Mark this
+        * key on as if it was on matrix position n_cols (ie
+        * one higher than the size of the matrix).
+        */
+       if (col == 0xFF)
+               return 1 << kp->n_cols;
+       else
+               return col & ((1 << kp->n_cols) - 1);
+}
+
+static int omap_kp_read_kp_matrix_state(struct omap_keypad *kp, u16 *state)
+{
+       u8 new_state[MAX_ROWS];
+       int row;
+       int ret = twl4030_kpread(kp, TWL4030_MODULE_KEYPAD,
+                                new_state, KEYP_FULL_CODE_7_0, kp->n_rows);
+       if (ret >= 0) {
+               for (row = 0; row < kp->n_rows; row++)
+                       state[row] = omap_kp_col_xlate(kp, new_state[row]);
+       }
+       return ret;
+}
+
+static int omap_kp_is_in_ghost_state(struct omap_keypad *kp, u16 *key_state)
+{
+       int i;
+       u16 check = 0;
+
+       for (i = 0; i < kp->n_rows; i++) {
+               u16 col = key_state[i];
+
+               if ((col & check) && hweight16(col) > 1)
+                       return 1;
+               check |= col;
+       }
+
+       return 0;
+}
+
+static void twl4030_kp_scan(struct omap_keypad *kp, int release_all)
+{
+       u16 new_state[MAX_ROWS];
+       int col, row;
+
+       if (release_all)
+               memset(new_state, 0, sizeof(new_state));
+       else {
+               /* check for any changes */
+               int ret = omap_kp_read_kp_matrix_state(kp, new_state);
+               if (ret < 0)    /* panic ... */
+                       return;
+
+               if (omap_kp_is_in_ghost_state(kp, new_state))
+                       return;
+       }
+
+       mutex_lock(&kp->mutex);
+
+       /* check for changes and print those */
+       for (row = 0; row < kp->n_rows; row++) {
+               int changed = new_state[row] ^ kp->kp_state[row];
+
+               if (!changed)
+                       continue;
+
+               for (col = 0; col < kp->n_cols + 1; col++) {
+                       int key;
+
+                       if (!(changed & (1 << col)))
+                               continue;
+
+                       dev_dbg(kp->dbg_dev, "key [%d:%d] %s\n", row, col,
+                               (new_state[row] & (1 << col)) ?
+                               "press" : "release");
+
+                       key = omap_kp_find_key(kp, col, row);
+                       if (key < 0)
+                               dev_warn(kp->dbg_dev,
+                                       "Spurious key event %d-%d\n",
+                                        col, row);
+                       else
+                               input_report_key(kp->omap_twl4030kp, key,
+                                                new_state[row] & (1 << col));
+               }
+               kp->kp_state[row] = new_state[row];
+       }
+
+       mutex_unlock(&kp->mutex);
+}
+
+/*
+ * Keypad interrupt handler
+ */
+static irqreturn_t do_kp_irq(int irq, void *_kp)
+{
+       struct omap_keypad *kp = _kp;
+       u8 reg;
+       int ret;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       /* Read & Clear TWL4030 pending interrupt */
+       ret = twl4030_kpread(kp, TWL4030_MODULE_KEYPAD, &reg, KEYP_ISR1, 1);
+
+       /* Release all keys if I2C has gone bad or
+        * the KEYP has gone to idle state */
+       if ((ret >= 0) && (reg & KEYP_IMR1_KP))
+               twl4030_kp_scan(kp, 0);
+       else
+               twl4030_kp_scan(kp, 1);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Registers keypad device with input sub system
+ * and configures TWL4030 keypad registers
+ */
+static int __init omap_kp_probe(struct platform_device *pdev)
+{
+       u8 reg;
+       int i;
+       int ret = 0;
+       struct omap_keypad *kp;
+       struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
+
+       kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+       if (!kp)
+               return -ENOMEM;
+
+       if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+               dev_err(&pdev->dev, "No rows, cols or keymap from pdata\n");
+               kfree(kp);
+               return -EINVAL;
+       }
+
+       dev_set_drvdata(&pdev->dev, kp);
+
+       /* Get the debug Device */
+       kp->dbg_dev = &pdev->dev;
+
+       kp->omap_twl4030kp = input_allocate_device();
+       if (!kp->omap_twl4030kp) {
+               kfree(kp);
+               return -ENOMEM;
+       }
+
+       mutex_init(&kp->mutex);
+
+       kp->keymap = pdata->keymap;
+       kp->keymapsize = pdata->keymapsize;
+       kp->n_rows = pdata->rows;
+       kp->n_cols = pdata->cols;
+       kp->irq = pdata->irq;
+
+       /* setup input device */
+       set_bit(EV_KEY, kp->omap_twl4030kp->evbit);
+
+       /* Enable auto repeat feature of Linux input subsystem */
+       if (pdata->rep)
+               set_bit(EV_REP, kp->omap_twl4030kp->evbit);
+
+       for (i = 0; i < kp->keymapsize; i++)
+               set_bit(kp->keymap[i] & KEYNUM_MASK,
+                               kp->omap_twl4030kp->keybit);
+
+       kp->omap_twl4030kp->name        = "omap_twl4030keypad";
+       kp->omap_twl4030kp->phys        = "omap_twl4030keypad/input0";
+       kp->omap_twl4030kp->dev.parent  = &pdev->dev;
+
+       kp->omap_twl4030kp->id.bustype  = BUS_HOST;
+       kp->omap_twl4030kp->id.vendor   = 0x0001;
+       kp->omap_twl4030kp->id.product  = 0x0001;
+       kp->omap_twl4030kp->id.version  = 0x0003;
+
+       kp->omap_twl4030kp->keycode     = kp->keymap;
+       kp->omap_twl4030kp->keycodesize = sizeof(unsigned int);
+       kp->omap_twl4030kp->keycodemax  = kp->keymapsize;
+
+       ret = input_register_device(kp->omap_twl4030kp);
+       if (ret < 0) {
+               dev_err(kp->dbg_dev,
+                       "Unable to register twl4030 keypad device\n");
+               goto err2;
+       }
+
+       /* Disable auto-repeat */
+       reg = KEYP_CTRL_NOAUTORPT;
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_CTRL);
+       if (ret < 0)
+               goto err3;
+
+       /* Enable TO rising and KP rising and falling edge detection */
+       reg = KEYP_EDR_KP_BOTH | KEYP_EDR_TO_RISING;
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_EDR);
+       if (ret < 0)
+               goto err3;
+
+       /* Set PTV prescaler Field */
+       reg = (PTV_PRESCALER << KEYP_LK_PTV_PTV_SHIFT);
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, reg, KEYP_LK_PTV);
+       if (ret < 0)
+               goto err3;
+
+       /* Set key debounce time to 20 ms */
+       i = KEYP_PERIOD_US(20000, PTV_PRESCALER);
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, i, KEYP_DEB);
+       if (ret < 0)
+               goto err3;
+
+       /* Set timeout period to 100 ms */
+       i = KEYP_PERIOD_US(200000, PTV_PRESCALER);
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD,
+                                (i & 0xFF), KEYP_TIMEOUT_L);
+       if (ret < 0)
+               goto err3;
+
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD,
+                                (i >> 8), KEYP_TIMEOUT_H);
+       if (ret < 0)
+               goto err3;
+
+       /* Enable Clear-on-Read */
+       reg = KEYP_SIH_CTRL_COR | KEYP_SIH_CTRL_PEND_DIS;
+       ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD,
+                                reg, KEYP_SIH_CTRL);
+       if (ret < 0)
+               goto err3;
+
+       /*
+        * This ISR will always execute in kernel thread context because of
+        * the need to access the TWL4030 over the I2C bus.
+        */
+       ret = request_irq(kp->irq, do_kp_irq, 0, pdev->name, kp);
+       if (ret < 0) {
+               dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n",
+                       kp->irq);
+               goto err3;
+       } else {
+               /* Enable KP and TO interrupts now. */
+               reg = ~(KEYP_IMR1_KP | KEYP_IMR1_TO);
+               ret = twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD,
+                                        reg, KEYP_IMR1);
+               if (ret < 0)
+                       goto err5;
+       }
+
+       ret = omap_kp_read_kp_matrix_state(kp, kp->kp_state);
+       if (ret < 0)
+               goto err4;
+
+       return ret;
+err5:
+       /* mask all events - we don't care about the result */
+       (void) twl4030_kpwrite_u8(kp, TWL4030_MODULE_KEYPAD, 0xff, KEYP_IMR1);
+err4:
+       free_irq(kp->irq, NULL);
+err3:
+       input_unregister_device(kp->omap_twl4030kp);
+err2:
+       input_free_device(kp->omap_twl4030kp);
+
+       return -ENODEV;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+       struct omap_keypad *kp = dev_get_drvdata(&pdev->dev);
+
+       free_irq(kp->irq, kp);
+       input_unregister_device(kp->omap_twl4030kp);
+       kfree(kp);
+
+       return 0;
+}
+
+
+static struct platform_driver omap_kp_driver = {
+       .probe          = omap_kp_probe,
+       .remove         = __devexit_p(omap_kp_remove),
+       .driver         = {
+               .name   = "twl4030_keypad",
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*
+ * OMAP TWL4030 Keypad init
+ */
+static int __devinit omap_kp_init(void)
+{
+       return platform_driver_register(&omap_kp_driver);
+}
+
+static void __exit omap_kp_exit(void)
+{
+       platform_driver_unregister(&omap_kp_driver);
+}
+
+module_init(omap_kp_init);
+module_exit(omap_kp_exit);
+MODULE_ALIAS("platform:twl4030_keypad");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("OMAP TWL4030 Keypad Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/tsc2301_kp.c b/drivers/input/keyboard/tsc2301_kp.c
new file mode 100644 (file)
index 0000000..a974a5f
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * TSC2301 keypad driver
+ *
+ * Copyright (C) 2005-2006 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen
+ * Rewritten by Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include <linux/spi/tsc2301.h>
+
+#define TSC2301_KEYBOARD_PRODUCT_ID      0x0051
+#define TSC2301_KEYBOARD_PRODUCT_VERSION 0x0001
+#define TSC2301_DEBOUNCE_TIME_2MS        0x0000
+#define TSC2301_DEBOUNCE_TIME_10MS       0x0800
+#define TSC2301_DEBOUNCE_TIME_20MS       0x1000
+#define TSC2301_DEBOUNCE_TIME_50MS       0x1800
+#define TSC2301_DEBOUNCE_TIME_60MS       0x2000
+#define TSC2301_DEBOUNCE_TIME_80MS       0x2800
+#define TSC2301_DEBOUNCE_TIME_100MS      0x3000
+#define TSC2301_DEBOUNCE_TIME_120MS      0x3800
+
+#define TSC2301_DEBOUNCE_TIME          TSC2301_DEBOUNCE_TIME_20MS
+
+#define TSC2301_RELEASE_TIMEOUT                50
+
+struct tsc2301_kp {
+       struct input_dev        *idev;
+       char                    phys[32];
+       spinlock_t              lock;
+       struct mutex            mutex;
+       struct timer_list       timer;
+       u16                     keys_pressed;
+       unsigned                pending:1;
+       unsigned                user_disabled:1;
+       unsigned                disable_depth;
+
+       struct spi_transfer     read_xfer[4];
+       struct spi_message      read_msg;
+
+       u16                     data;
+       u16                     mask;
+
+       int                     irq;
+       s16                     keymap[16];
+};
+
+static inline int tsc2301_kp_disabled(struct tsc2301 *tsc)
+{
+       return tsc->kp->disable_depth != 0;
+}
+
+static void tsc2301_kp_send_key_events(struct tsc2301 *tsc,
+                                      u16 prev_state,
+                                      u16 new_state)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       u16 common, released, pressed;
+       int i;
+
+       common = prev_state & new_state;
+       released = common ^ prev_state;
+       pressed = common ^ new_state;
+       if (!released && !pressed)
+               return;
+       for (i = 0; i < 16 && (released || pressed); i++) {
+               if (released & 1) {
+                       dev_dbg(&tsc->spi->dev, "key %d released\n", i);
+                       input_report_key(kp->idev, kp->keymap[i], 0);
+               }
+               released >>= 1;
+               if (pressed & 1) {
+                       dev_dbg(&tsc->spi->dev, "key %d pressed\n", i);
+                       input_report_key(kp->idev, kp->keymap[i], 1);
+               }
+               pressed >>= 1;
+       }
+       input_sync(kp->idev);
+}
+
+static inline void _filter_out(struct tsc2301 *tsc, u16 prev_state,
+                              u16 *new_state, int row1, int row2, u8 rect_pat)
+{
+       u16 mask;
+
+       mask = (rect_pat << (row1 * 4)) | (rect_pat << (row2 * 4));
+       mask &= ~prev_state;
+       *new_state &= ~mask;
+       dev_dbg(&tsc->spi->dev, "filtering ghost keys %02x\n", mask);
+}
+
+static void tsc2301_filter_ghost_keys(struct tsc2301 *tsc, u16 prev_state,
+                                     u16 *new_state)
+{
+       int row1, row2;
+       u16 key_map;
+       u16 row1_map;
+       static const u8 rect_pat[] = {
+               0x3, 0x5, 0x9, 0x6, 0xa, 0xc, 0,
+       };
+
+       key_map = *new_state;
+       for (row1 = 0; row1 < 4; row1++) {
+               row1_map = (key_map >> (row1 * 4)) & 0xf;
+               if (!row1_map)
+                       continue;
+               for (row2 = row1 + 1; row2 < 4; row2++) {
+                       u16 rect_map = (key_map >> (row2 * 4)) & 0xf;
+                       const u8 *rp;
+
+                       rect_map &= row1_map;
+                       if (!rect_map)
+                               continue;
+                       for (rp = rect_pat; *rp; rp++)
+                               if ((rect_map & *rp) == *rp)
+                                       _filter_out(tsc, prev_state, new_state,
+                                                   row1, row2, *rp);
+               }
+       }
+}
+
+static void tsc2301_kp_timer(unsigned long arg)
+{
+       struct tsc2301 *tsc = (void *) arg;
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       tsc2301_kp_send_key_events(tsc, kp->keys_pressed, 0);
+       spin_lock_irqsave(&kp->lock, flags);
+       kp->keys_pressed = 0;
+       spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static void tsc2301_kp_rx(void *arg)
+{
+       struct tsc2301 *tsc = arg;
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+       u16 kp_data;
+
+       kp_data = kp->data;
+       dev_dbg(&tsc->spi->dev, "KP data %04x\n", kp_data);
+
+       tsc2301_filter_ghost_keys(tsc, kp->keys_pressed, &kp_data);
+       tsc2301_kp_send_key_events(tsc, kp->keys_pressed, kp_data);
+       spin_lock_irqsave(&kp->lock, flags);
+       kp->keys_pressed = kp_data;
+       kp->pending = 0;
+       spin_unlock_irqrestore(&kp->lock, flags);
+}
+
+static irqreturn_t tsc2301_kp_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2301 *tsc = dev_id;
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+       int r;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       if (tsc2301_kp_disabled(tsc)) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               return IRQ_HANDLED;
+       }
+       kp->pending = 1;
+       spin_unlock_irqrestore(&kp->lock, flags);
+       mod_timer(&kp->timer,
+                jiffies + msecs_to_jiffies(TSC2301_RELEASE_TIMEOUT));
+       r = spi_async(tsc->spi, &tsc->kp->read_msg);
+       if (r)
+               dev_err(&tsc->spi->dev, "kp: spi_async() failed");
+       return IRQ_HANDLED;
+}
+
+static void tsc2301_kp_start_scan(struct tsc2301 *tsc)
+{
+       tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, tsc->kp->mask);
+       tsc2301_write_reg(tsc, TSC2301_REG_KEY, TSC2301_DEBOUNCE_TIME);
+}
+
+static void tsc2301_kp_stop_scan(struct tsc2301 *tsc)
+{
+       tsc2301_write_reg(tsc, TSC2301_REG_KEY, 1 << 14);
+}
+
+/* Must be called with the mutex held */
+static void tsc2301_kp_enable(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       BUG_ON(!tsc2301_kp_disabled(tsc));
+       if (--kp->disable_depth != 0) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       set_irq_type(kp->irq, IRQ_TYPE_EDGE_FALLING);
+       tsc2301_kp_start_scan(tsc);
+       enable_irq(kp->irq);
+}
+
+/* Must be called with the mutex held */
+static int tsc2301_kp_disable(struct tsc2301 *tsc, int release_keys)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&kp->lock, flags);
+       if (kp->disable_depth++ != 0) {
+               spin_unlock_irqrestore(&kp->lock, flags);
+               goto out;
+       }
+       disable_irq_nosync(kp->irq);
+       set_irq_type(kp->irq, IRQ_TYPE_NONE);
+       spin_unlock_irqrestore(&kp->lock, flags);
+
+       while (kp->pending) {
+               msleep(1);
+       }
+
+       tsc2301_kp_stop_scan(tsc);
+out:
+       if (!release_keys)
+               del_timer(&kp->timer); /* let timeout release keys */
+
+       return 0;
+}
+
+/* The following workaround is needed for a HW bug triggered by the
+ * following:
+ * 1. keep any key pressed
+ * 2. disable keypad
+ * 3. release all keys
+ * 4. reenable keypad
+ * 5. disable touch screen controller
+ *
+ * After this the keypad scanner will get stuck in busy state and won't
+ * report any interrupts for further keypresses. One way to recover is to
+ * restart the keypad scanner whenever we enable / disable the
+ * touchscreen controller.
+ */
+void tsc2301_kp_restart(struct tsc2301 *tsc)
+{
+       if (!tsc2301_kp_disabled(tsc)) {
+               tsc2301_kp_start_scan(tsc);
+       }
+}
+
+static ssize_t tsc2301_kp_disable_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", tsc2301_kp_disabled(tsc) ? 1 : 0);
+}
+
+static ssize_t tsc2301_kp_disable_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_kp       *kp = tsc->kp;
+       char *endp;
+       int i;
+
+       i = simple_strtoul(buf, &endp, 10);
+       i = i ? 1 : 0;
+
+       mutex_lock(&kp->mutex);
+       if (i == kp->user_disabled) {
+               mutex_unlock(&kp->mutex);
+               return count;
+       }
+       kp->user_disabled = i;
+
+       if (i)
+               tsc2301_kp_disable(tsc, 1);
+       else
+               tsc2301_kp_enable(tsc);
+       mutex_unlock(&kp->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(disable_kp, 0664, tsc2301_kp_disable_show,
+                  tsc2301_kp_disable_store);
+
+static const u16 tsc2301_kp_read_data = 0x8000 | TSC2301_REG_KPDATA;
+
+static void tsc2301_kp_setup_spi_xfer(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+       struct spi_message *m = &kp->read_msg;
+       struct spi_transfer *x = &kp->read_xfer[0];
+
+       spi_message_init(&kp->read_msg);
+
+       x->tx_buf = &tsc2301_kp_read_data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+       x++;
+
+       x->rx_buf = &kp->data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       m->complete = tsc2301_kp_rx;
+       m->context = tsc;
+}
+
+#ifdef CONFIG_PM
+int tsc2301_kp_suspend(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       mutex_lock(&kp->mutex);
+       tsc2301_kp_disable(tsc, 1);
+       mutex_unlock(&kp->mutex);
+       return 0;
+}
+
+void tsc2301_kp_resume(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       mutex_lock(&kp->mutex);
+       tsc2301_kp_enable(tsc);
+       mutex_unlock(&kp->mutex);
+}
+#endif
+
+int __devinit tsc2301_kp_init(struct tsc2301 *tsc,
+                             struct tsc2301_platform_data *pdata)
+{
+       struct input_dev *idev;
+       struct tsc2301_kp *kp;
+       int r, i;
+       u16 mask;
+
+       if (pdata->keyb_int < 0) {
+               dev_err(&tsc->spi->dev, "need kbirq");
+               return -EINVAL;
+       }
+
+       kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+       if (kp == NULL)
+               return -ENOMEM;
+       tsc->kp = kp;
+
+       kp->irq = pdata->keyb_int;
+       spin_lock_init(&kp->lock);
+       mutex_init(&kp->mutex);
+
+       init_timer(&kp->timer);
+       kp->timer.data = (unsigned long) tsc;
+       kp->timer.function = tsc2301_kp_timer;
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err1;
+       }
+       if (pdata->keyb_name)
+               idev->name = pdata->keyb_name;
+       else
+               idev->name = "TSC2301 keypad";
+       snprintf(kp->phys, sizeof(kp->phys), "%s/input-kp", tsc->spi->dev.bus_id);
+       idev->phys = kp->phys;
+
+       mask = 0;
+       idev->evbit[0] = BIT(EV_KEY);
+       for (i = 0; i < 16; i++) {
+               if (pdata->keymap[i] > 0) {
+                       set_bit(pdata->keymap[i], idev->keybit);
+                       kp->keymap[i] = pdata->keymap[i];
+               } else {
+                       kp->keymap[i] = -1;
+                       mask |= 1 << i;
+               }
+       }
+
+       if (pdata->kp_rep)
+               set_bit(EV_REP, idev->evbit);
+
+       kp->idev = idev;
+
+       tsc2301_kp_setup_spi_xfer(tsc);
+
+       r = device_create_file(&tsc->spi->dev, &dev_attr_disable_kp);
+       if (r < 0)
+               goto err2;
+
+       tsc2301_kp_start_scan(tsc);
+
+       /* IRQ mode 0 is faulty, it can cause the KBIRQ to get stuck.
+        * Mode 2 deasserts the IRQ at:
+        * - HW or SW reset
+        * - Setting SCS flag in REG_KEY register
+        * - Releasing all keys
+        * - Reading the REG_KPDATA
+        */
+       tsc2301_write_kbc(tsc, 2);
+
+       tsc2301_write_reg(tsc, TSC2301_REG_KPMASK, mask);
+       kp->mask = mask;
+
+       set_irq_type(kp->irq, IRQ_TYPE_EDGE_FALLING);
+
+       r = request_irq(kp->irq, tsc2301_kp_irq_handler, IRQF_SAMPLE_RANDOM,
+                       "tsc2301-kp", tsc);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get kbirq IRQ");
+               goto err3;
+       }
+       set_irq_wake(kp->irq, 1);
+
+       /* We need to read the register once..? */
+       tsc2301_read_reg(tsc, TSC2301_REG_KPDATA);
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "can't register keypad device\n");
+               goto err4;
+       }
+
+       return 0;
+
+err4:
+       free_irq(kp->irq, tsc);
+err3:
+       tsc2301_kp_stop_scan(tsc);
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+err2:
+       input_free_device(kp->idev);
+err1:
+       kfree(kp);
+       return r;
+}
+
+void __devexit tsc2301_kp_exit(struct tsc2301 *tsc)
+{
+       struct tsc2301_kp *kp = tsc->kp;
+
+       tsc2301_kp_disable(tsc, 1);
+       input_unregister_device(kp->idev);
+       free_irq(kp->irq, tsc);
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_kp);
+
+       kfree(kp);
+}
diff --git a/drivers/input/keyboard/twl4030-keypad.h b/drivers/input/keyboard/twl4030-keypad.h
new file mode 100644 (file)
index 0000000..b903a77
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * drivers/input/keyboard/twl4030-keypad.h
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ *
+ * Intial Code:
+ *     Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __TWL4030_KEYPAD_H__
+#define __TWL4030_KEYPAD_H__
+
+/* Register Definitions */
+#define KEYP_CTRL                              0x00
+#define KEYP_DEB                               0x01
+#define KEYP_LONG_KEY                          0x02
+#define KEYP_LK_PTV                            0x03
+#define KEYP_TIMEOUT_L                         0x04
+#define KEYP_TIMEOUT_H                         0x05
+#define KEYP_FULL_CODE_7_0                     0x09
+#define KEYP_ISR1                              0x11
+#define KEYP_IMR1                              0x12
+#define KEYP_EDR                               0x16
+#define KEYP_SIH_CTRL                          0x17
+
+/* KEYP_CTRL_REG Fields */
+#define KEYP_CTRL_SOFT_NRST                    0x01
+#define KEYP_CTRL_SOFTMODEN                    0x02
+#define KEYP_CTRL_LK_EN                                0x04
+#define KEYP_CTRL_TOE_EN                       0x08
+#define KEYP_CTRL_TOLE_EN                      0x10
+#define KEYP_CTRL_RP_EN                                0x20
+#define KEYP_CTRL_KBD_ON                       0x40
+
+
+#define KEYP_CTRL_NOAUTORPT                    (KEYP_CTRL_SOFT_NRST |  \
+                                                KEYP_CTRL_SOFTMODEN |  \
+                                                KEYP_CTRL_TOE_EN |     \
+                                                KEYP_CTRL_KBD_ON)
+
+/* KEYP_DEB, KEYP_LONG_KEY, KEYP_TIMEOUT_x*/
+#define KEYP_PERIOD_US(T, prescale)            (T / (31 << (prescale + 1)) - 1)
+
+/* KEYP_LK_PTV_REG Fields */
+#define KEYP_LK_PTV_PTV_SHIFT                  5
+
+/* KEYP_IMR1 Fields */
+#define KEYP_IMR1_MIS                          0x08
+#define KEYP_IMR1_TO                           0x04
+#define KEYP_IMR1_LK                           0x02
+#define KEYP_IMR1_KP                           0x01
+
+/* KEYP_EDR Fields */
+#define KEYP_EDR_KP_FALLING                    0x01
+#define KEYP_EDR_KP_RISING                     0x02
+#define KEYP_EDR_KP_BOTH                       0x03
+#define KEYP_EDR_LK_FALLING                    0x04
+#define KEYP_EDR_LK_RISING                     0x08
+#define KEYP_EDR_TO_FALLING                    0x10
+#define KEYP_EDR_TO_RISING                     0x20
+#define KEYP_EDR_MIS_FALLING                   0x40
+#define KEYP_EDR_MIS_RISING                    0x80
+
+/* KEYP_SIH_CTRL Fields */
+#define KEYP_SIH_CTRL_COR                      0x04
+#define KEYP_SIH_CTRL_PEND_DIS                 0x02
+#define KEYP_SIH_CTRL_EXCL_EN                  0x01
+
+#endif /* End of __TWL4030-KEYPAD_H__ */
index 25287e80e236727f70bffef85bc0a6d782c44543..d33f450243dfe45189ce0449bf92656cc0a5c15b 100644 (file)
@@ -217,6 +217,46 @@ config TOUCHSCREEN_ATMEL_TSADCC
          To compile this driver as a module, choose M here: the
          module will be called atmel_tsadcc.
 
+config TOUCHSCREEN_TSC2005
+       tristate "TSC2005 touchscreen support"
+       help
+         Say Y here for if you are using the touchscreen features of TSC2005.
+
+config TOUCHSCREEN_TSC2102
+       tristate "TSC 2102 based touchscreens"
+       depends on SPI_MASTER
+       select SPI_TSC2102
+       help
+         Say Y here if you have a touchscreen interface using the
+         TI TSC 2102 controller, and your board-specific initialization
+         code includes that in its table of SPI devices.  Also make
+         sure the proper SPI controller is selected.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2102_ts.
+
+config TOUCHSCREEN_TSC210X
+       tristate "TI TSC210x based touchscreens"
+       depends on SPI_MASTER
+       select SPI_TSC210X
+       help
+         Say Y here if you have a touchscreen interface using a
+         TI TSC210x controller, and your board-specific initialisation
+         code includes that in its table of SPI devices.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc210x_ts.
+
+config TOUCHSCREEN_TSC2301
+       tristate "TSC2301 touchscreen support"
+       depends on SPI_TSC2301
+       help
+         Say Y here for if you are using the touchscreen features of TSC2301.
+
 config TOUCHSCREEN_UCB1400
        tristate "Philips UCB1400 touchscreen"
        select AC97_BUS
index 15cf2907948952df00b961ad2f0d97407b4a2faa..0c31dfa3ac9c984dd7281b628801c2bab364d512 100644 (file)
@@ -26,6 +26,11 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)   += touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)     += touchwin.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)      += ucb1400_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2005)      += tsc2005.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2102)      += tsc2102_ts.o
+obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
+obj-$(CONFIG_TOUCHSCREEN_TSC210X)      += tsc210x_ts.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2301)      += tsc2301_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)       += wm97xx-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
index ce6f48c695f553a703a9c9af3c739996bc2c971c..cc1db125a14a5d0d6f0e9cb568ee43ebab9bd328 100644 (file)
@@ -826,6 +826,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                return -ENODEV;
        }
 
+       /* enable voltage */
+       if (pdata->vaux_control != NULL) {
+               err = pdata->vaux_control(VAUX_ENABLE);
+               if (err != 0) {
+                       dev_dbg(&spi->dev, "TS vaux enable failed\n");
+                       return err;
+               }
+       }
+
        /* don't exceed max specified sample rate */
        if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
                dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
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..ee85755
--- /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[BIT_WORD(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       ts_omap.inputdevice->absbit[0] =
+           BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       input_register_device(ts_omap.inputdevice);
+
+       ts_omap.dev->enable();
+
+       printk("OMAP touchscreen driver initialized\n");
+
+       return 0;
+}
+
+static int omap_ts_remove(struct platform_device *pdev)
+{
+       ts_omap.dev->disable();
+       input_unregister_device(ts_omap.inputdevice);
+       if (ts_omap.irq != -1)
+               free_irq(ts_omap.irq, &ts_omap);
+
+       ts_omap.dev->remove();
+
+       return 0;
+}
+
+static int omap_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       ts_omap.dev->disable();
+       return 0;
+}
+
+static int omap_ts_resume(struct platform_device *pdev)
+{
+       ts_omap.dev->enable();
+       return 0;
+}
+
+static void omap_ts_device_release(struct device *dev)
+{
+       /* Nothing */
+}
+static struct platform_driver omap_ts_driver = {
+       .probe          = omap_ts_probe,
+       .remove         = omap_ts_remove,
+       .suspend        = omap_ts_suspend,
+       .resume         = omap_ts_resume,
+       .driver = {
+               .name   = OMAP_TS_NAME,
+       },
+};
+
+static struct platform_device omap_ts_device = {
+       .name           = OMAP_TS_NAME,
+       .id             = -1,
+       .dev = {
+               .release        = omap_ts_device_release,
+       },
+};
+
+static int __init omap_ts_init(void)
+{
+       int ret;
+
+       if (machine_is_omap_osk() || machine_is_omap_innovator())
+               return -ENODEV;
+
+       ret = platform_device_register(&omap_ts_device);
+       if (ret != 0)
+               return -ENODEV;
+
+       ret = platform_driver_register(&omap_ts_driver);
+       if (ret != 0) {
+               platform_device_unregister(&omap_ts_device);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit omap_ts_exit(void)
+{
+       platform_driver_unregister(&omap_ts_driver);
+       platform_device_unregister(&omap_ts_device);
+}
+
+module_init(omap_ts_init);
+module_exit(omap_ts_exit);
+
+MODULE_LICENSE("GPL");
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/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
new file mode 100644 (file)
index 0000000..7fb107e
--- /dev/null
@@ -0,0 +1,736 @@
+/*
+ * TSC2005 touchscreen driver
+ *
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <mach/gpio.h>
+#endif
+
+#include <linux/spi/tsc2005.h>
+
+/**
+ * The touchscreen interface operates as follows:
+ *
+ * Initialize:
+ *    Request access to GPIO103 (DAV)
+ *    tsc2005_dav_irq_handler will trigger when DAV line goes down
+ *
+ *  1) Pen is pressed against touchscreeen
+ *  2) TSC2005 performs AD conversion
+ *  3) After the conversion is done TSC2005 drives DAV line down
+ *  4) GPIO IRQ is received and tsc2005_dav_irq_handler is called
+ *  5) tsc2005_ts_irq_handler queues up an spi transfer to fetch
+ *     the x, y, z1, z2 values
+ *  6) tsc2005_ts_rx() reports coordinates to input layer and
+ *     sets up tsc2005_ts_timer() to be called after TSC2005_TS_SCAN_TIME
+ *  7)  When the penup_timer expires, there have not been DAV interrupts
+ *     during the last 20ms which means the pen has been lifted.
+ */
+
+#define TSC2005_VDD_LOWER_27
+
+#ifdef TSC2005_VDD_LOWER_27
+#define TSC2005_HZ     (10000000)
+#else
+#define TSC2005_HZ     (25000000)
+#endif
+
+#define TSC2005_CMD    (0x80)
+#define TSC2005_REG    (0x00)
+
+#define TSC2005_CMD_STOP       (1)
+#define TSC2005_CMD_10BIT      (0 << 2)
+#define TSC2005_CMD_12BIT      (1 << 2)
+
+#define TSC2005_CMD_SCAN_XYZZ  (0 << 3)
+#define TSC2005_CMD_SCAN_XY    (1 << 3)
+#define TSC2005_CMD_SCAN_X     (2 << 3)
+#define TSC2005_CMD_SCAN_Y     (3 << 3)
+#define TSC2005_CMD_SCAN_ZZ    (4 << 3)
+#define TSC2005_CMD_AUX_SINGLE (5 << 3)
+#define TSC2005_CMD_TEMP1      (6 << 3)
+#define TSC2005_CMD_TEMP2      (7 << 3)
+#define TSC2005_CMD_AUX_CONT   (8 << 3)
+#define TSC2005_CMD_TEST_X_CONN        (9 << 3)
+#define TSC2005_CMD_TEST_Y_CONN        (10 << 3)
+/* command 11 reserved */
+#define TSC2005_CMD_TEST_SHORT (12 << 3)
+#define TSC2005_CMD_DRIVE_XX   (13 << 3)
+#define TSC2005_CMD_DRIVE_YY   (14 << 3)
+#define TSC2005_CMD_DRIVE_YX   (15 << 3)
+
+#define TSC2005_REG_X          (0 << 3)
+#define TSC2005_REG_Y          (1 << 3)
+#define TSC2005_REG_Z1         (2 << 3)
+#define TSC2005_REG_Z2         (3 << 3)
+#define TSC2005_REG_AUX                (4 << 3)
+#define TSC2005_REG_TEMP1      (5 << 3)
+#define TSC2005_REG_TEMP2      (6 << 3)
+#define TSC2005_REG_STATUS     (7 << 3)
+#define TSC2005_REG_AUX_HIGH   (8 << 3)
+#define TSC2005_REG_AUX_LOW    (9 << 3)
+#define TSC2005_REG_TEMP_HIGH  (10 << 3)
+#define TSC2005_REG_TEMP_LOW   (11 << 3)
+#define TSC2005_REG_CFR0       (12 << 3)
+#define TSC2005_REG_CFR1       (13 << 3)
+#define TSC2005_REG_CFR2       (14 << 3)
+#define TSC2005_REG_FUNCTION   (15 << 3)
+
+#define TSC2005_REG_PND0       (1 << 1)
+#define TSC2005_REG_READ       (0x01)
+#define TSC2005_REG_WRITE      (0x00)
+
+
+#define TSC2005_CFR0_LONGSAMPLING      (1)
+#define TSC2005_CFR0_DETECTINWAIT      (1 << 1)
+#define TSC2005_CFR0_SENSETIME_32US    (0)
+#define TSC2005_CFR0_SENSETIME_96US    (1 << 2)
+#define TSC2005_CFR0_SENSETIME_544US   (1 << 3)
+#define TSC2005_CFR0_SENSETIME_2080US  (1 << 4)
+#define TSC2005_CFR0_SENSETIME_2656US  (0x001C)
+#define TSC2005_CFR0_PRECHARGE_20US    (0x0000)
+#define TSC2005_CFR0_PRECHARGE_84US    (0x0020)
+#define TSC2005_CFR0_PRECHARGE_276US   (0x0040)
+#define TSC2005_CFR0_PRECHARGE_1044US  (0x0080)
+#define TSC2005_CFR0_PRECHARGE_1364US  (0x00E0)
+#define TSC2005_CFR0_STABTIME_0US      (0x0000)
+#define TSC2005_CFR0_STABTIME_100US    (0x0100)
+#define TSC2005_CFR0_STABTIME_500US    (0x0200)
+#define TSC2005_CFR0_STABTIME_1MS      (0x0300)
+#define TSC2005_CFR0_STABTIME_5MS      (0x0400)
+#define TSC2005_CFR0_STABTIME_100MS    (0x0700)
+#define TSC2005_CFR0_CLOCK_4MHZ                (0x0000)
+#define TSC2005_CFR0_CLOCK_2MHZ                (0x0800)
+#define TSC2005_CFR0_CLOCK_1MHZ                (0x1000)
+#define TSC2005_CFR0_RESOLUTION12      (0x2000)
+#define TSC2005_CFR0_STATUS            (0x4000)
+#define TSC2005_CFR0_PENMODE           (0x8000)
+
+#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS  |   \
+                                TSC2005_CFR0_CLOCK_1MHZ    |   \
+                                TSC2005_CFR0_RESOLUTION12  |   \
+                                TSC2005_CFR0_PRECHARGE_276US | \
+                                TSC2005_CFR0_PENMODE)
+
+#define TSC2005_CFR1_BATCHDELAY_0MS    (0x0000)
+#define TSC2005_CFR1_BATCHDELAY_1MS    (0x0001)
+#define TSC2005_CFR1_BATCHDELAY_2MS    (0x0002)
+#define TSC2005_CFR1_BATCHDELAY_4MS    (0x0003)
+#define TSC2005_CFR1_BATCHDELAY_10MS   (0x0004)
+#define TSC2005_CFR1_BATCHDELAY_20MS   (0x0005)
+#define TSC2005_CFR1_BATCHDELAY_40MS   (0x0006)
+#define TSC2005_CFR1_BATCHDELAY_100MS  (0x0007)
+
+#define TSC2005_CFR1_INITVALUE (TSC2005_CFR1_BATCHDELAY_2MS)
+
+#define TSC2005_CFR2_MAVE_TEMP (0x0001)
+#define TSC2005_CFR2_MAVE_AUX  (0x0002)
+#define TSC2005_CFR2_MAVE_Z    (0x0004)
+#define TSC2005_CFR2_MAVE_Y    (0x0008)
+#define TSC2005_CFR2_MAVE_X    (0x0010)
+#define TSC2005_CFR2_AVG_1     (0x0000)
+#define TSC2005_CFR2_AVG_3     (0x0400)
+#define TSC2005_CFR2_AVG_7     (0x0800)
+#define TSC2005_CFR2_MEDIUM_1  (0x0000)
+#define TSC2005_CFR2_MEDIUM_3  (0x1000)
+#define TSC2005_CFR2_MEDIUM_7  (0x2000)
+#define TSC2005_CFR2_MEDIUM_15 (0x3000)
+
+#define TSC2005_CFR2_IRQ_DAV   (0x4000)
+#define TSC2005_CFR2_IRQ_PEN   (0x8000)
+#define TSC2005_CFR2_IRQ_PENDAV        (0x0000)
+
+#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_IRQ_DAV   |       \
+                                TSC2005_CFR2_MAVE_X    |       \
+                                TSC2005_CFR2_MAVE_Y    |       \
+                                TSC2005_CFR2_MAVE_Z    |       \
+                                TSC2005_CFR2_MEDIUM_15 |       \
+                                TSC2005_CFR2_AVG_7)
+
+#define MAX_12BIT                                      ((1 << 12) - 1)
+#define TS_SAMPLES                                     4
+#define TS_RECT_SIZE                                   8
+#define TSC2005_TS_PENUP_TIME                          20
+
+static const u32 tsc2005_read_reg[] = {
+       (TSC2005_REG | TSC2005_REG_X | TSC2005_REG_READ) << 16,
+       (TSC2005_REG | TSC2005_REG_Y | TSC2005_REG_READ) << 16,
+       (TSC2005_REG | TSC2005_REG_Z1 | TSC2005_REG_READ) << 16,
+       (TSC2005_REG | TSC2005_REG_Z2 | TSC2005_REG_READ) << 16,
+};
+#define NUM_READ_REGS  (sizeof(tsc2005_read_reg)/sizeof(tsc2005_read_reg[0]))
+
+struct tsc2005 {
+       struct spi_device       *spi;
+
+       struct input_dev        *idev;
+       char                    phys[32];
+       struct timer_list       penup_timer;
+       spinlock_t              lock;
+       struct mutex            mutex;
+
+       struct spi_message      read_msg;
+       struct spi_transfer     read_xfer[NUM_READ_REGS];
+       u32                     data[NUM_READ_REGS];
+
+       /* previous x,y,z */
+       int                     x;
+       int                     y;
+       int                     p;
+       /* average accumulators for each component */
+       int                     sample_cnt;
+       int                     avg_x;
+       int                     avg_y;
+       int                     avg_z1;
+       int                     avg_z2;
+       /* configuration */
+       int                     x_plate_ohm;
+       int                     hw_avg_max;
+       int                     stab_time;
+       int                     p_max;
+       int                     touch_pressure;
+       int                     irq;
+       s16                     dav_gpio;
+       /* status */
+       u8                      sample_sent;
+       u8                      pen_down;
+       u8                      disabled;
+       u8                      disable_depth;
+       u8                      spi_active;
+};
+
+static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+{
+       u16 data = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+       struct spi_message msg;
+       struct spi_transfer xfer = { 0 };
+
+       xfer.tx_buf = &data;
+       xfer.rx_buf = NULL;
+       xfer.len = 1;
+       xfer.bits_per_word = 8;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value)
+{
+       u32 tx;
+       struct spi_message msg;
+       struct spi_transfer xfer = { 0 };
+
+       tx = (TSC2005_REG | reg | TSC2005_REG_PND0 |
+              TSC2005_REG_WRITE) << 16;
+       tx |= value;
+
+       xfer.tx_buf = &tx;
+       xfer.rx_buf = NULL;
+       xfer.len = 4;
+       xfer.bits_per_word = 24;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       spi_sync(ts->spi, &msg);
+}
+
+static void tsc2005_ts_update_pen_state(struct tsc2005 *ts,
+                                       int x, int y, int pressure)
+{
+       if (pressure) {
+               input_report_abs(ts->idev, ABS_X, x);
+               input_report_abs(ts->idev, ABS_Y, y);
+               input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+               if (!ts->pen_down) {
+                       input_report_key(ts->idev, BTN_TOUCH, 1);
+                       ts->pen_down = 1;
+               }
+       } else {
+               input_report_abs(ts->idev, ABS_PRESSURE, 0);
+               if (ts->pen_down) {
+                       input_report_key(ts->idev, BTN_TOUCH, 0);
+                       ts->pen_down = 0;
+               }
+       }
+
+       input_sync(ts->idev);
+}
+
+/*
+ * This function is called by the SPI framework after the coordinates
+ * have been read from TSC2005
+ */
+static void tsc2005_ts_rx(void *arg)
+{
+       struct tsc2005 *ts = arg;
+       unsigned long flags;
+       int inside_rect, pressure_limit;
+       int x, y, z1, z2, pressure;
+
+       spin_lock_irqsave(&ts->lock, flags);
+
+       x = ts->data[0];
+       y = ts->data[1];
+       z1 = ts->data[2];
+       z2 = ts->data[3];
+
+       /* validate pressure and position */
+       if (x > MAX_12BIT || y > MAX_12BIT)
+               goto out;
+
+       /* skip coords if the pressure-components are out of range */
+       if (z1 < 100 || z2 > 4000)
+               goto out;
+
+       /* don't run average on the "pen down" event */
+       if (ts->sample_sent) {
+               ts->avg_x += x;
+               ts->avg_y += y;
+               ts->avg_z1 += z1;
+               ts->avg_z2 += z2;
+
+               if (++ts->sample_cnt < TS_SAMPLES)
+                       goto out;
+
+               x = ts->avg_x / TS_SAMPLES;
+               y = ts->avg_y / TS_SAMPLES;
+               z1 = ts->avg_z1 / TS_SAMPLES;
+               z2 = ts->avg_z2 / TS_SAMPLES;
+       }
+
+       ts->sample_cnt = 0;
+       ts->avg_x = 0;
+       ts->avg_y = 0;
+       ts->avg_z1 = 0;
+       ts->avg_z2 = 0;
+
+       if (z1) {
+               pressure = x * (z2 - z1) / z1;
+               pressure = pressure * ts->x_plate_ohm / 4096;
+       } else
+               goto out;
+
+       pressure_limit = ts->sample_sent? ts->p_max: ts->touch_pressure;
+       if (pressure > pressure_limit)
+               goto out;
+
+       /* discard the event if it still is within the previous rect - unless
+        * if the pressure is harder, but then use previous x,y position */
+       inside_rect = (ts->sample_sent &&
+               x > (int)ts->x - TS_RECT_SIZE &&
+               x < (int)ts->x + TS_RECT_SIZE &&
+               y > (int)ts->y - TS_RECT_SIZE &&
+               y < (int)ts->y + TS_RECT_SIZE);
+       if (inside_rect)
+               x = ts->x, y = ts->y;
+
+       if (!inside_rect || pressure < ts->p) {
+               tsc2005_ts_update_pen_state(ts, x, y, pressure);
+               ts->sample_sent = 1;
+               ts->x = x;
+               ts->y = y;
+               ts->p = pressure;
+       }
+out:
+       ts->spi_active = 0;
+       spin_unlock_irqrestore(&ts->lock, flags);
+
+       /* kick pen up timer - to make sure it expires again(!) */
+       if (ts->sample_sent)
+               mod_timer(&ts->penup_timer,
+                         jiffies + msecs_to_jiffies(TSC2005_TS_PENUP_TIME));
+}
+
+static void tsc2005_ts_penup_timer_handler(unsigned long data)
+{
+       struct tsc2005 *ts = (struct tsc2005 *)data;
+
+       if (ts->sample_sent) {
+               tsc2005_ts_update_pen_state(ts, 0, 0, 0);
+               ts->sample_sent = 0;
+       }
+}
+
+/*
+ * This interrupt is called when pen is down and coordinates are
+ * available. That is indicated by a falling edge on DAV line.
+ */
+static irqreturn_t tsc2005_ts_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2005 *ts = dev_id;
+       int r;
+
+       if (ts->spi_active)
+               return IRQ_HANDLED;
+
+       ts->spi_active = 1;
+       r = spi_async(ts->spi, &ts->read_msg);
+       if (r)
+               dev_err(&ts->spi->dev, "ts: spi_async() failed");
+
+       /* kick pen up timer */
+       mod_timer(&ts->penup_timer,
+                 jiffies + msecs_to_jiffies(TSC2005_TS_PENUP_TIME));
+
+       return IRQ_HANDLED;
+}
+
+static void tsc2005_ts_setup_spi_xfer(struct tsc2005 *ts)
+{
+       struct spi_message *m = &ts->read_msg;
+       struct spi_transfer *x = &ts->read_xfer[0];
+       int i;
+
+       spi_message_init(m);
+
+       for (i = 0; i < NUM_READ_REGS; i++, x++) {
+               x->tx_buf = &tsc2005_read_reg[i];
+               x->rx_buf = &ts->data[i];
+               x->len = 4;
+               x->bits_per_word = 24;
+               x->cs_change = i < (NUM_READ_REGS - 1);
+               spi_message_add_tail(x, m);
+       }
+
+       m->complete = tsc2005_ts_rx;
+       m->context = ts;
+}
+
+static ssize_t tsc2005_ts_pen_down_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct tsc2005 *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", tsc->pen_down);
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2005_ts_pen_down_show, NULL);
+
+static int tsc2005_configure(struct tsc2005 *tsc, int flags)
+{
+       tsc2005_write(tsc, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
+       tsc2005_write(tsc, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
+       tsc2005_write(tsc, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
+       tsc2005_cmd(tsc, flags);
+
+       return 0;
+}
+
+static void tsc2005_start_scan(struct tsc2005 *tsc)
+{
+       tsc2005_configure(tsc, TSC2005_CMD_SCAN_XYZZ);
+}
+
+static void tsc2005_stop_scan(struct tsc2005 *tsc)
+{
+       tsc2005_cmd(tsc, TSC2005_CMD_STOP);
+}
+
+/* Must be called with mutex held */
+static void tsc2005_disable(struct tsc2005 *ts)
+{
+       if (ts->disable_depth++ != 0)
+               return;
+
+       disable_irq(ts->irq);
+
+       /* wait until penup timer expire normally */
+       do {
+               msleep(4);
+       } while (ts->sample_sent);
+
+       tsc2005_stop_scan(ts);
+}
+
+static void tsc2005_enable(struct tsc2005 *ts)
+{
+       if (--ts->disable_depth != 0)
+               return;
+
+       enable_irq(ts->irq);
+
+       tsc2005_start_scan(ts);
+}
+
+static ssize_t tsc2005_disable_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct tsc2005 *ts = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2005_disable_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct tsc2005          *tsc = dev_get_drvdata(dev);
+       unsigned long res;
+       int i;
+
+       i = strict_strtoul(buf, 10, &res);
+       i = i ? 1 : 0;
+
+       mutex_lock(&tsc->mutex);
+       if (i == tsc->disabled)
+               goto out;
+       tsc->disabled = i;
+
+       if (i)
+               tsc2005_disable(tsc);
+       else
+               tsc2005_enable(tsc);
+out:
+       mutex_unlock(&tsc->mutex);
+       return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2005_disable_show,
+                  tsc2005_disable_store);
+
+
+static int __devinit tsc2005_ts_init(struct tsc2005 *ts,
+                                    struct tsc2005_platform_data *pdata)
+{
+       struct input_dev *idev;
+       int dav_gpio, r;
+       int x_max, y_max;
+       int x_fudge, y_fudge, p_fudge;
+
+       if (pdata->dav_gpio < 0) {
+               dev_err(&ts->spi->dev, "need DAV GPIO");
+               return -EINVAL;
+       }
+       dav_gpio = pdata->dav_gpio;
+       ts->dav_gpio = dav_gpio;
+       dev_dbg(&ts->spi->dev, "TSC2005: DAV GPIO = %d\n", dav_gpio);
+
+#ifdef CONFIG_ARCH_OMAP
+       r = omap_request_gpio(dav_gpio);
+       if (r < 0) {
+               dev_err(&ts->spi->dev, "unable to get DAV GPIO");
+               goto err1;
+       }
+       omap_set_gpio_direction(dav_gpio, 1);
+       ts->irq = OMAP_GPIO_IRQ(dav_gpio);
+       dev_dbg(&ts->spi->dev, "TSC2005: DAV IRQ = %d\n", ts->irq);
+#endif
+       init_timer(&ts->penup_timer);
+       setup_timer(&ts->penup_timer, tsc2005_ts_penup_timer_handler,
+                       (unsigned long)ts);
+
+       spin_lock_init(&ts->lock);
+       mutex_init(&ts->mutex);
+
+       ts->x_plate_ohm         = pdata->ts_x_plate_ohm ? : 280;
+       ts->hw_avg_max          = pdata->ts_hw_avg;
+       ts->stab_time           = pdata->ts_stab_time;
+       x_max                   = pdata->ts_x_max ? : 4096;
+       x_fudge                 = pdata->ts_x_fudge ? : 4;
+       y_max                   = pdata->ts_y_max ? : 4096;
+       y_fudge                 = pdata->ts_y_fudge ? : 8;
+       ts->p_max               = pdata->ts_pressure_max ? : MAX_12BIT;
+       ts->touch_pressure      = pdata->ts_touch_pressure ? : ts->p_max;
+       p_fudge                 = pdata->ts_pressure_fudge ? : 2;
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err2;
+       }
+
+       idev->name = "TSC2005 touchscreen";
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts",
+                ts->spi->dev.bus_id);
+       idev->phys = ts->phys;
+
+       idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+       idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       ts->idev = idev;
+
+       tsc2005_ts_setup_spi_xfer(ts);
+
+       input_set_abs_params(idev, ABS_X, 0, x_max, x_fudge, 0);
+       input_set_abs_params(idev, ABS_Y, 0, y_max, y_fudge, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, ts->p_max, p_fudge, 0);
+
+       tsc2005_start_scan(ts);
+
+       r = request_irq(ts->irq, tsc2005_ts_irq_handler,
+                       IRQF_TRIGGER_FALLING | IRQF_DISABLED |
+                       IRQF_SAMPLE_RANDOM, "tsc2005", ts);
+       if (r < 0) {
+               dev_err(&ts->spi->dev, "unable to get DAV IRQ");
+               goto err3;
+       }
+
+       set_irq_wake(ts->irq, 1);
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&ts->spi->dev, "can't register touchscreen device\n");
+               goto err4;
+       }
+
+       /* We can tolerate these failing */
+       if (device_create_file(&ts->spi->dev, &dev_attr_pen_down));
+       if (device_create_file(&ts->spi->dev, &dev_attr_disable_ts));
+
+       return 0;
+err4:
+       free_irq(ts->irq, ts);
+err3:
+       tsc2005_stop_scan(ts);
+       input_free_device(idev);
+err2:
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(dav_gpio);
+#endif
+err1:
+       return r;
+}
+
+static int __devinit tsc2005_probe(struct spi_device *spi)
+{
+       struct tsc2005                  *tsc;
+       struct tsc2005_platform_data    *pdata = spi->dev.platform_data;
+       int r;
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+       if (tsc == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(&spi->dev, tsc);
+       tsc->spi = spi;
+       spi->dev.power.power_state = PMSG_ON;
+
+       spi->mode = SPI_MODE_0;
+       spi->bits_per_word = 8;
+       /* The max speed might've been defined by the board-specific
+        * struct */
+       if (!spi->max_speed_hz)
+               spi->max_speed_hz = TSC2005_HZ;
+
+       spi_setup(spi);
+
+       r = tsc2005_ts_init(tsc, pdata);
+       if (r)
+               goto err1;
+
+       return 0;
+
+err1:
+       kfree(tsc);
+       return r;
+}
+
+static int __devexit tsc2005_remove(struct spi_device *spi)
+{
+       struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+       mutex_lock(&ts->mutex);
+       tsc2005_disable(ts);
+       mutex_unlock(&ts->mutex);
+
+       device_remove_file(&ts->spi->dev, &dev_attr_disable_ts);
+       device_remove_file(&ts->spi->dev, &dev_attr_pen_down);
+
+       free_irq(ts->irq, ts);
+       input_unregister_device(ts->idev);
+
+#ifdef CONFIG_ARCH_OMAP
+       omap_free_gpio(ts->dav_gpio);
+#endif
+       kfree(ts);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+       mutex_lock(&ts->mutex);
+       tsc2005_disable(ts);
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+
+static int tsc2005_resume(struct spi_device *spi)
+{
+       struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
+
+       mutex_lock(&ts->mutex);
+       tsc2005_enable(ts);
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+#endif
+
+static struct spi_driver tsc2005_driver = {
+       .driver = {
+               .name = "tsc2005",
+               .owner = THIS_MODULE,
+       },
+#ifdef CONFIG_PM
+       .suspend = tsc2005_suspend,
+       .resume = tsc2005_resume,
+#endif
+       .probe = tsc2005_probe,
+       .remove = __devexit_p(tsc2005_remove),
+};
+
+static int __init tsc2005_init(void)
+{
+       printk(KERN_INFO "TSC2005 driver initializing\n");
+
+       return spi_register_driver(&tsc2005_driver);
+}
+module_init(tsc2005_init);
+
+static void __exit tsc2005_exit(void)
+{
+       spi_unregister_driver(&tsc2005_driver);
+}
+module_exit(tsc2005_exit);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tsc2005");
diff --git a/drivers/input/touchscreen/tsc2102_ts.c b/drivers/input/touchscreen/tsc2102_ts.c
new file mode 100644 (file)
index 0000000..b6ed927
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * input/touchscreen/tsc2102_ts.c
+ *
+ * Touchscreen input device driver for the TSC 2102 chip.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc2102.h>
+
+struct input_dev *dev;
+
+static void tsc2102_touch(int touching)
+{
+       if (!touching) {
+               input_report_abs(dev, ABS_X, 0);
+               input_report_abs(dev, ABS_Y, 0);
+               input_report_abs(dev, ABS_PRESSURE, 0);
+               input_sync(dev);
+       }
+
+       input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc2102_coords(int x, int y, int z1, int z2)
+{
+       int p;
+
+       /* Calculate the touch resistance a la equation #1 */
+       if (z1 != 0)
+               p = x * (z2 - z1) / (z1 << 4);
+       else
+               p = 1;
+
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_report_abs(dev, ABS_PRESSURE, p);
+       input_sync(dev);
+}
+
+static int tsc2102_ts_probe(struct platform_device *pdev)
+{
+       int status;
+
+       dev = input_allocate_device();
+       if (!dev)
+               return -ENOMEM;
+
+       status = tsc2102_touch_cb(tsc2102_touch);
+       if (status) {
+               input_free_device(dev);
+               return status;
+       }
+
+       status = tsc2102_coords_cb(tsc2102_coords);
+       if (status) {
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       dev->name = "TSC2102 Touchscreen";
+       dev->cdev.dev = &pdev->dev;
+       dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       dev->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
+       dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       dev->phys = "tsc2102/input0";
+       dev->id.bustype = BUS_HOST;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x2102;
+       dev->id.version = 0x0001;
+
+       status = input_register_device(dev);
+       if (status) {
+               tsc2102_coords_cb(0);
+               tsc2102_touch_cb(0);
+               input_free_device(dev);
+               return status;
+       }
+
+       printk(KERN_INFO "TSC2102 touchscreen driver initialized\n");
+       return 0;
+}
+
+static int tsc2102_ts_remove(struct platform_device *pdev)
+{
+       tsc2102_touch_cb(0);
+       tsc2102_coords_cb(0);
+       input_unregister_device(dev);
+       input_free_device(dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+tsc2102_ts_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       return 0;
+}
+
+static int tsc2102_ts_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+#else
+#define tsc2102_ts_suspend     NULL
+#define tsc2102_ts_resume      NULL
+#endif
+
+static struct platform_driver tsc2102_ts_driver = {
+       .probe          = tsc2102_ts_probe,
+       .remove         = tsc2102_ts_remove,
+       .suspend        = tsc2102_ts_suspend,
+       .resume         = tsc2102_ts_resume,
+       .driver         = {
+               .name   = "tsc2102-ts",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tsc2102_ts_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&tsc2102_ts_driver);
+       if (ret)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit tsc2102_ts_exit(void)
+{
+       platform_driver_unregister(&tsc2102_ts_driver);
+}
+
+module_init(tsc2102_ts_init);
+module_exit(tsc2102_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2102.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc210x_ts.c b/drivers/input/touchscreen/tsc210x_ts.c
new file mode 100644 (file)
index 0000000..5828b6d
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * tsc210x_ts.c - touchscreen input device for TI TSC210x chips
+ *
+ * Copyright (c) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/tsc210x.h>
+
+
+/*
+ * The sensor ADC on tsc210x chips is most often used with the smart
+ * touchscreen controller.   Those controllers can be made to improve
+ * sample quality directly by multi-sampling and by taking the mean or
+ * median of various numbers of samples.  They also take X, Y, and
+ * pressure measurements automatically, so this driver has relatively
+ * little to do.
+ *
+ * There are a few chips in this family that don't have quite the same
+ * touchscreen interface, e.g. no "median" mode.
+ */
+
+static void tsc210x_touch(void *context, int touching)
+{
+       struct input_dev *dev = context;
+
+       if (!touching) {
+               input_report_abs(dev, ABS_X, 0);
+               input_report_abs(dev, ABS_Y, 0);
+               input_report_abs(dev, ABS_PRESSURE, 0);
+               input_sync(dev);
+       }
+
+       input_report_key(dev, BTN_TOUCH, touching);
+}
+
+static void tsc210x_coords(void *context, int x, int y, int z1, int z2)
+{
+       struct input_dev *dev = context;
+       int p;
+
+       /* Calculate the touch resistance a la equation #1 */
+       if (z1 != 0)
+               p = x * (z2 - z1) / (z1 << 4);
+       else
+               p = 1;
+
+       input_report_abs(dev, ABS_X, x);
+       input_report_abs(dev, ABS_Y, y);
+       input_report_abs(dev, ABS_PRESSURE, p);
+       input_sync(dev);
+}
+
+static int tsc210x_ts_probe(struct platform_device *pdev)
+{
+       int status;
+       struct input_dev *dev;
+
+       dev = input_allocate_device();
+       if (!dev)
+               return -ENOMEM;
+
+       status = tsc210x_touch_cb(pdev->dev.parent, tsc210x_touch, dev);
+       if (status) {
+               input_free_device(dev);
+               return status;
+       }
+
+       status = tsc210x_coords_cb(pdev->dev.parent, tsc210x_coords, dev);
+       if (status) {
+               tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+               input_free_device(dev);
+               return status;
+       }
+
+       dev->name = "TSC210x Touchscreen";
+       dev->dev.parent = &pdev->dev;
+       dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
+       dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       dev->phys = "tsc210x/input0";
+       dev->id.bustype = BUS_HOST;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x2100;
+       dev->id.version = 0x0001;
+
+       status = input_register_device(dev);
+       if (status) {
+               tsc210x_coords_cb(pdev->dev.parent, NULL, NULL);
+               tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+               input_free_device(dev);
+               return status;
+       }
+
+       platform_set_drvdata(pdev, dev);
+       printk(KERN_INFO "TSC210x touchscreen initialised\n");
+       return 0;
+}
+
+static int __exit tsc210x_ts_remove(struct platform_device *pdev)
+{
+       struct input_dev *dev = platform_get_drvdata(pdev);
+
+       tsc210x_touch_cb(pdev->dev.parent, NULL, NULL);
+       tsc210x_coords_cb(pdev->dev.parent, NULL, NULL);
+       platform_set_drvdata(pdev, NULL);
+       input_unregister_device(dev);
+       input_free_device(dev);
+
+       return 0;
+}
+
+static struct platform_driver tsc210x_ts_driver = {
+       .probe          = tsc210x_ts_probe,
+       .remove         = __exit_p(tsc210x_ts_remove),
+       /* Nothing to do on suspend/resume */
+       .driver         = {
+               .name   = "tsc210x-ts",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tsc210x_ts_init(void)
+{
+       /* can't use driver_probe() here since the parent device
+        * gets registered "late"
+        */
+       return platform_driver_register(&tsc210x_ts_driver);
+}
+module_init(tsc210x_ts_init);
+
+static void __exit tsc210x_ts_exit(void)
+{
+       platform_driver_unregister(&tsc210x_ts_driver);
+}
+module_exit(tsc210x_ts_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Touchscreen input driver for TI TSC2101/2102.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2301_ts.c b/drivers/input/touchscreen/tsc2301_ts.c
new file mode 100644 (file)
index 0000000..6462cc2
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * TSC2301 touchscreen driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation
+ *
+ * Written by Jarkko Oikarinen, Imre Deak and Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+
+#include <linux/spi/tsc2301.h>
+
+/**
+ * The touchscreen interface operates as follows:
+ *
+ * Initialize:
+ *    Request access to GPIO103 (DAV)
+ *    tsc2301_ts_irq_handler will trigger when DAV line goes down
+ *
+ *  1) Pen is pressed against touchscreeen
+ *  2) TSC2301 performs AD conversion
+ *  3) After the conversion is done TSC2301 drives DAV line down
+ *  4) GPIO IRQ is received and tsc2301_ts_irq_handler is called
+ *  5) tsc2301_ts_irq_handler queues up an spi transfer to fetch
+ *     the x, y, z1, z2 values
+ *  6) SPI framework calls tsc2301_ts_rx after the coordinates are read
+ *  7) When the penup_timer expires, there have not been DAV interrupts
+ *     during the last 20ms which means the pen has been lifted.
+ */
+
+
+#define TSC2301_TOUCHSCREEN_PRODUCT_ID                 0x0052
+#define TSC2301_TOUCHSCREEN_PRODUCT_VERSION            0x0001
+
+#define TSC2301_TS_PENUP_TIME                          20
+
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301      0x8000
+#define TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST         0x0000
+
+#define TSC2301_ADCREG_FUNCTION_NONE                   0x0000
+#define TSC2301_ADCREG_FUNCTION_XY                     0x0400
+#define TSC2301_ADCREG_FUNCTION_XYZ                    0x0800
+#define TSC2301_ADCREG_FUNCTION_X                      0x0C00
+#define TSC2301_ADCREG_FUNCTION_Y                      0x1000
+#define TSC2301_ADCREG_FUNCTION_Z                      0x1400
+#define TSC2301_ADCREG_FUNCTION_DAT1                   0x1800
+#define TSC2301_ADCREG_FUNCTION_DAT2                   0x1C00
+#define TSC2301_ADCREG_FUNCTION_AUX1                   0x2000
+#define TSC2301_ADCREG_FUNCTION_AUX2                   0x2400
+#define TSC2301_ADCREG_FUNCTION_TEMP                   0x2800
+
+#define TSC2301_ADCREG_RESOLUTION_8BIT                 0x0100
+#define TSC2301_ADCREG_RESOLUTION_10BIT                        0x0200
+#define TSC2301_ADCREG_RESOLUTION_12BIT                        0x0300
+
+#define TSC2301_ADCREG_AVERAGING_NONE                  0x0000
+#define TSC2301_ADCREG_AVERAGING_4AVG                  0x0040
+#define TSC2301_ADCREG_AVERAGING_8AVG                  0x0080
+#define TSC2301_ADCREG_AVERAGING_16AVG                 0x00C0
+
+#define TSC2301_ADCREG_CLOCK_8MHZ                      0x0000
+#define TSC2301_ADCREG_CLOCK_4MHZ                      0x0010
+#define TSC2301_ADCREG_CLOCK_2MHZ                      0x0020
+#define TSC2301_ADCREG_CLOCK_1MHZ                      0x0030
+
+#define TSC2301_ADCREG_VOLTAGE_STAB_0US                        0x0000
+#define TSC2301_ADCREG_VOLTAGE_STAB_100US              0x0002
+#define TSC2301_ADCREG_VOLTAGE_STAB_500US              0x0004
+#define TSC2301_ADCREG_VOLTAGE_STAB_1MS                        0x0006
+#define TSC2301_ADCREG_VOLTAGE_STAB_5MS                        0x0008
+#define TSC2301_ADCREG_VOLTAGE_STAB_10MS               0x000A
+#define TSC2301_ADCREG_VOLTAGE_STAB_50MS               0x000C
+#define TSC2301_ADCREG_VOLTAGE_STAB_100MS              0x000E
+
+#define TSC2301_ADCREG_STOP_CONVERSION                 0x4000
+
+#define MAX_12BIT                                      ((1 << 12) - 1)
+
+#define TS_RECT_SIZE                                   8
+#define TSF_MIN_Z1                                     100
+#define TSF_MAX_Z2                                     4000
+
+#define TSF_SAMPLES                                    4
+
+struct ts_filter {
+       int                     sample_cnt;
+
+       int                     avg_x;
+       int                     avg_y;
+       int                     avg_z1;
+       int                     avg_z2;
+};
+
+struct ts_coords {
+       u16                     x;
+       u16                     y;
+       u16                     z1;
+       u16                     z2;
+};
+
+struct tsc2301_ts {
+       struct input_dev        *idev;
+       char                    phys[32];
+       struct timer_list       penup_timer;
+       struct mutex            mutex;
+
+       struct spi_transfer     read_xfer[2];
+       struct spi_message      read_msg;
+       struct ts_coords        *coords;
+
+       struct ts_filter        filter;
+
+       int                     hw_avg_max;
+       u16                     x;
+       u16                     y;
+       u16                     p;
+
+       u16                     x_plate_ohm;
+       int                     stab_time;
+       int                     max_pressure;
+       int                     touch_pressure;
+
+       u8                      event_sent;
+       u8                      pen_down;
+       u8                      disabled;
+       u8                      disable_depth;
+
+       int                     hw_flags;
+       int                     irq;
+};
+
+
+static const u16 tsc2301_ts_read_data = 0x8000 | TSC2301_REG_X;
+
+static int tsc2301_ts_check_config(struct tsc2301_ts *ts, int *hw_flags)
+{
+       int flags;
+
+       flags = 0;
+       switch (ts->hw_avg_max) {
+       case 0:
+               flags |= TSC2301_ADCREG_AVERAGING_NONE;
+               break;
+       case 4:
+               flags |= TSC2301_ADCREG_AVERAGING_4AVG;
+               break;
+       case 8:
+               flags |= TSC2301_ADCREG_AVERAGING_8AVG;
+               break;
+       case 16:
+               flags |= TSC2301_ADCREG_AVERAGING_16AVG;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (ts->stab_time) {
+       case 0:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_0US;
+               break;
+       case 100:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_100US;
+               break;
+       case 500:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_500US;
+               break;
+       case 1000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_1MS;
+               break;
+       case 5000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_5MS;
+               break;
+       case 10000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_10MS;
+               break;
+       case 50000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_50MS;
+               break;
+       case 100000:
+               flags |= TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       *hw_flags = flags;
+       return 0;
+}
+
+/*
+ * This odd three-time initialization is to work around a bug in TSC2301.
+ * See TSC2301 errata for details.
+ */
+static int tsc2301_ts_configure(struct tsc2301 *tsc, int flags)
+{
+       struct spi_transfer xfer[5];
+       struct spi_transfer *x;
+       struct spi_message m;
+       int i;
+       u16 val1, val2, val3;
+       u16 data[10];
+
+       val1 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+               TSC2301_ADCREG_STOP_CONVERSION |
+               TSC2301_ADCREG_FUNCTION_NONE |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_AVERAGING_NONE |
+               TSC2301_ADCREG_CLOCK_2MHZ |
+               TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+       val2 = TSC2301_ADCREG_CONVERSION_CTRL_BY_HOST |
+               TSC2301_ADCREG_FUNCTION_XYZ |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_AVERAGING_16AVG |
+               TSC2301_ADCREG_CLOCK_1MHZ |
+               TSC2301_ADCREG_VOLTAGE_STAB_100MS;
+
+       /* Averaging and voltage stabilization settings in flags */
+       val3 = TSC2301_ADCREG_CONVERSION_CTRL_BY_TSC2301 |
+               TSC2301_ADCREG_FUNCTION_XYZ |
+               TSC2301_ADCREG_RESOLUTION_12BIT |
+               TSC2301_ADCREG_CLOCK_2MHZ |
+               flags;
+
+       /* Now we prepare the command for transferring */
+       data[0] = TSC2301_REG_ADC;
+       data[1] = val1;
+       data[2] = TSC2301_REG_ADC;
+       data[3] = val2;
+       data[4] = TSC2301_REG_ADC;
+       data[5] = val3;
+       data[6] = TSC2301_REG_REF;
+       data[7] = 1 << 4 | 1 << 2 | 1; /* intref, 100uS settl, 2.5V ref */
+       data[8] = TSC2301_REG_CONFIG;
+       data[9] = 3 << 3 | 2 << 0; /* 340uS pre-chrg, 544us delay */
+
+       spi_message_init(&m);
+       m.spi = tsc->spi;
+
+       memset(xfer, 0, sizeof(xfer));
+       x = &xfer[0];
+
+       for (i = 0; i < 10; i += 2) {
+               x->tx_buf = &data[i];
+               x->len = 4;
+               if (i != 8)
+                       x->cs_change = 1;
+               spi_message_add_tail(x, &m);
+               x++;
+       }
+       spi_sync(m.spi, &m);
+
+       return 0;
+}
+
+static void tsc2301_ts_start_scan(struct tsc2301 *tsc)
+{
+       tsc2301_ts_configure(tsc, tsc->ts->hw_flags);
+       tsc2301_kp_restart(tsc);
+}
+
+static void tsc2301_ts_stop_scan(struct tsc2301 *tsc)
+{
+       tsc2301_write_reg(tsc, TSC2301_REG_ADC, TSC2301_ADCREG_STOP_CONVERSION);
+       tsc2301_kp_restart(tsc);
+}
+
+static void update_pen_state(struct tsc2301_ts *ts, int x, int y, int pressure)
+{
+       if (pressure) {
+               input_report_abs(ts->idev, ABS_X, x);
+               input_report_abs(ts->idev, ABS_Y, y);
+               input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+               if (!ts->pen_down)
+                       input_report_key(ts->idev, BTN_TOUCH, 1);
+               ts->pen_down = 1;
+       } else {
+               input_report_abs(ts->idev, ABS_PRESSURE, 0);
+               if (ts->pen_down)
+                       input_report_key(ts->idev, BTN_TOUCH, 0);
+               ts->pen_down = 0;
+       }
+
+       input_sync(ts->idev);
+
+#ifdef VERBOSE
+       dev_dbg(&tsc->spi->dev, "x %4d y %4d p %4d\n", x, y, pressure);
+#endif
+}
+
+static int filter(struct tsc2301_ts *ts, int x, int y, int z1, int z2)
+{
+       int inside_rect, pressure_limit, Rt;
+       struct ts_filter *tsf = &ts->filter;
+
+       /* validate pressure and position */
+       if (x > MAX_12BIT || y > MAX_12BIT)
+               return 0;
+
+       /* skip coords if the pressure-components are out of range */
+       if (z1 < TSF_MIN_Z1 || z2 > TSF_MAX_Z2)
+               return 0;
+
+       /* Use the x,y,z1,z2 directly on the first "pen down" event */
+       if (ts->event_sent) {
+               tsf->avg_x  += x;
+               tsf->avg_y  += y;
+               tsf->avg_z1 += z1;
+               tsf->avg_z2 += z2;
+
+               if (++tsf->sample_cnt < TSF_SAMPLES)
+                       return 0;
+               x = tsf->avg_x / TSF_SAMPLES;
+               y = tsf->avg_y / TSF_SAMPLES;
+               z1 = tsf->avg_z1 / TSF_SAMPLES;
+               z2 = tsf->avg_z2 / TSF_SAMPLES;
+       }
+       tsf->sample_cnt = 0;
+       tsf->avg_x  = 0;
+       tsf->avg_y  = 0;
+       tsf->avg_z1 = 0;
+       tsf->avg_z2 = 0;
+
+       pressure_limit = ts->event_sent? ts->max_pressure: ts->touch_pressure;
+
+       /* z1 is always at least 100: */
+       Rt = x * (z2 - z1) / z1;
+       Rt = Rt * ts->x_plate_ohm / 4096;
+       if (Rt > pressure_limit)
+               return 0;
+
+       /* discard the event if it still is within the previous rect - unless
+        * if the pressure is harder, but then use previous x,y position */
+       inside_rect = (
+           x > (int)ts->x - TS_RECT_SIZE && x < (int)ts->x + TS_RECT_SIZE &&
+           y > (int)ts->y - TS_RECT_SIZE && y < (int)ts->y + TS_RECT_SIZE);
+
+       if (!ts->event_sent || !inside_rect) {
+               ts->x = x;
+               ts->y = y;
+               ts->p = Rt;
+               return 1;
+       } else if (Rt < ts->p) {
+               ts->p = Rt;
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * This procedure is called by the SPI framework after the coordinates
+ * have been read from TSC2301
+ */
+static void tsc2301_ts_rx(void *arg)
+{
+       struct tsc2301 *tsc = arg;
+       struct tsc2301_ts *ts = tsc->ts;
+       int send_event;
+       int x, y, z1, z2;
+
+       x  = ts->coords->x;
+       y  = ts->coords->y;
+       z1 = ts->coords->z1;
+       z2 = ts->coords->z2;
+
+       send_event = filter(ts, x, y, z1, z2);
+       if (send_event) {
+               update_pen_state(ts, ts->x, ts->y, ts->p);
+               ts->event_sent = 1;
+       }
+
+       mod_timer(&ts->penup_timer,
+                 jiffies + msecs_to_jiffies(TSC2301_TS_PENUP_TIME));
+}
+
+/*
+ * Timer is called TSC2301_TS_PENUP_TIME after pen is up
+ */
+static void tsc2301_ts_timer_handler(unsigned long data)
+{
+       struct tsc2301 *tsc = (struct tsc2301 *)data;
+       struct tsc2301_ts *ts = tsc->ts;
+
+       if (ts->event_sent) {
+               ts->event_sent = 0;
+               update_pen_state(ts, 0, 0, 0);
+       }
+}
+
+/*
+ * This interrupt is called when pen is down and coordinates are
+ * available. That is indicated by a falling edge on DEV line.
+ */
+static irqreturn_t tsc2301_ts_irq_handler(int irq, void *dev_id)
+{
+       struct tsc2301 *tsc = dev_id;
+       struct tsc2301_ts *ts = tsc->ts;
+       int r;
+
+       r = spi_async(tsc->spi, &ts->read_msg);
+       if (r)
+               dev_err(&tsc->spi->dev, "ts: spi_async() failed");
+
+       mod_timer(&ts->penup_timer,
+                 jiffies + msecs_to_jiffies(TSC2301_TS_PENUP_TIME));
+
+       return IRQ_HANDLED;
+}
+
+static void tsc2301_ts_disable(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       if (ts->disable_depth++ != 0)
+               return;
+
+       disable_irq(ts->irq);
+
+       /* wait until penup timer expire normally */
+       do {
+               msleep(1);
+       } while (ts->event_sent);
+
+       tsc2301_ts_stop_scan(tsc);
+}
+
+static void tsc2301_ts_enable(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       if (--ts->disable_depth != 0)
+               return;
+
+       enable_irq(ts->irq);
+
+       tsc2301_ts_start_scan(tsc);
+}
+
+#ifdef CONFIG_PM
+int tsc2301_ts_suspend(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       mutex_lock(&ts->mutex);
+       tsc2301_ts_disable(tsc);
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+
+void tsc2301_ts_resume(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       mutex_lock(&ts->mutex);
+       tsc2301_ts_enable(tsc);
+       mutex_unlock(&ts->mutex);
+}
+#endif
+
+static void tsc2301_ts_setup_spi_xfer(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+       struct spi_message *m = &ts->read_msg;
+       struct spi_transfer *x = &ts->read_xfer[0];
+
+       spi_message_init(m);
+
+       x->tx_buf = &tsc2301_ts_read_data;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       x++;
+       x->rx_buf = ts->coords;
+       x->len = 8;
+       spi_message_add_tail(x, m);
+
+       m->complete = tsc2301_ts_rx;
+       m->context = tsc;
+}
+
+static ssize_t tsc2301_ts_pen_down_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", tsc->ts->pen_down);
+}
+
+static DEVICE_ATTR(pen_down, S_IRUGO, tsc2301_ts_pen_down_show, NULL);
+
+static ssize_t tsc2301_ts_disable_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_ts       *ts = tsc->ts;
+
+       return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t tsc2301_ts_disable_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t count)
+{
+       struct tsc2301          *tsc = dev_get_drvdata(dev);
+       struct tsc2301_ts       *ts = tsc->ts;
+       char *endp;
+       int i;
+
+       i = simple_strtoul(buf, &endp, 10);
+       i = i ? 1 : 0;
+       mutex_lock(&ts->mutex);
+       if (i == ts->disabled) goto out;
+       ts->disabled = i;
+
+       if (i)
+               tsc2301_ts_disable(tsc);
+       else
+               tsc2301_ts_enable(tsc);
+out:
+       mutex_unlock(&ts->mutex);
+       return count;
+}
+
+static DEVICE_ATTR(disable_ts, 0664, tsc2301_ts_disable_show,
+                  tsc2301_ts_disable_store);
+
+int __devinit tsc2301_ts_init(struct tsc2301 *tsc,
+                             struct tsc2301_platform_data *pdata)
+{
+       struct tsc2301_ts *ts;
+       struct input_dev *idev;
+       int r;
+       int x_max, y_max;
+       int x_fudge, y_fudge, p_fudge;
+
+       if (pdata->dav_int <= 0) {
+               dev_err(&tsc->spi->dev, "need DAV IRQ");
+               return -EINVAL;
+       }
+
+       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+       if (ts == NULL)
+               return -ENOMEM;
+       tsc->ts = ts;
+
+       ts->coords = kzalloc(sizeof(*ts->coords), GFP_KERNEL);
+       if (ts->coords == NULL) {
+               kfree(ts);
+               return -ENOMEM;
+       }
+
+       ts->irq = pdata->dav_int;
+
+       init_timer(&ts->penup_timer);
+       setup_timer(&ts->penup_timer, tsc2301_ts_timer_handler,
+                       (unsigned long)tsc);
+
+       mutex_init(&ts->mutex);
+
+       ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280;
+       ts->hw_avg_max  = pdata->ts_hw_avg;
+       ts->max_pressure = pdata->ts_max_pressure ? : MAX_12BIT;
+       ts->touch_pressure = pdata->ts_touch_pressure ? : ts->max_pressure;
+       ts->stab_time   = pdata->ts_stab_time;
+
+       x_max           = pdata->ts_x_max ? : 4096;
+       y_max           = pdata->ts_y_max ? : 4096;
+       x_fudge         = pdata->ts_x_fudge ? : 4;
+       y_fudge         = pdata->ts_y_fudge ? : 8;
+       p_fudge         = pdata->ts_pressure_fudge ? : 2;
+
+       if ((r = tsc2301_ts_check_config(ts, &ts->hw_flags))) {
+               dev_err(&tsc->spi->dev, "invalid configuration\n");
+               goto err2;
+       }
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               r = -ENOMEM;
+               goto err2;
+       }
+       idev->name = "TSC2301 touchscreen";
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input-ts", tsc->spi->dev.bus_id);
+       idev->phys = ts->phys;
+       idev->dev.parent = &tsc->spi->dev;
+
+       idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+       idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       ts->idev = idev;
+
+       tsc2301_ts_setup_spi_xfer(tsc);
+
+       /* These parameters should perhaps be configurable? */
+       input_set_abs_params(idev, ABS_X, 0, x_max, x_fudge, 0);
+       input_set_abs_params(idev, ABS_Y, 0, y_max, y_fudge, 0);
+       input_set_abs_params(idev, ABS_PRESSURE, 0, ts->max_pressure,
+                            p_fudge, 0);
+
+       tsc2301_ts_start_scan(tsc);
+
+       r = request_irq(ts->irq, tsc2301_ts_irq_handler,
+                       IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+                       "tsc2301-ts", tsc);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "unable to get DAV IRQ");
+               goto err3;
+       }
+       set_irq_wake(ts->irq, 1);
+
+       if (device_create_file(&tsc->spi->dev, &dev_attr_pen_down) < 0)
+               goto err4;
+       if (device_create_file(&tsc->spi->dev, &dev_attr_disable_ts) < 0)
+               goto err5;
+
+       r = input_register_device(idev);
+       if (r < 0) {
+               dev_err(&tsc->spi->dev, "can't register touchscreen device\n");
+               goto err6;
+       }
+
+       return 0;
+err6:
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+err5:
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+err4:
+       free_irq(ts->irq, tsc);
+err3:
+       tsc2301_ts_stop_scan(tsc);
+       input_free_device(idev);
+err2:
+       kfree(ts->coords);
+       kfree(ts);
+       return r;
+}
+
+void __devexit tsc2301_ts_exit(struct tsc2301 *tsc)
+{
+       struct tsc2301_ts *ts = tsc->ts;
+
+       tsc2301_ts_disable(tsc);
+
+       device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
+       device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
+
+       free_irq(ts->irq, tsc);
+       input_unregister_device(ts->idev);
+
+       kfree(ts->coords);
+       kfree(ts);
+}
+MODULE_AUTHOR("Jarkko Oikarinen <jarkko.oikarinen@nokia.com>");
+MODULE_LICENSE("GPL");
index 9556262dda5aabba7b6474eee2b4e2a3b1a31906..6a2f44153c748ee22cf28ccba9e24d15579d00c2 100644 (file)
@@ -77,6 +77,27 @@ config LEDS_WRAP
        help
          This option enables support for the PCEngines WRAP programmable LEDs.
 
+config LEDS_OMAP_DEBUG
+       boolean "LED Support for OMAP debug board LEDs"
+       depends on LEDS_CLASS=y && ARCH_OMAP
+       help
+         Enables support for the LEDs on the debug board used with OMAP
+         reference boards like H2/H3/H4 and Perseus2.  Up to six of these
+         may be claimed by the original ARM debug LED API.
+
+config LEDS_OMAP
+       tristate "LED Support for OMAP GPIO LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP
+       help
+         This option enables support for the LEDs on OMAP processors.
+
+config LEDS_OMAP_PWM
+       tristate "LED Support for OMAP PWM-controlled LEDs"
+       depends on LEDS_CLASS && ARCH_OMAP && OMAP_DM_TIMER
+       help
+         This options enables support for LEDs connected to GPIO lines
+         controlled by a PWM timer on OMAP CPUs.
+
 config LEDS_H1940
        tristate "LED Support for iPAQ H1940 device"
        depends on LEDS_CLASS && ARCH_H1940
index ff7982b44565d7fe674b0846916a8acb2d221666..fd6316edf52d700a4e6195e6b99d56a9f4227b3f 100644 (file)
@@ -13,6 +13,8 @@ obj-$(CONFIG_LEDS_S3C24XX)            += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_AMS_DELTA)           += leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)             += leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
+obj-$(CONFIG_LEDS_OMAP)                        += leds-omap.o
+obj-$(CONFIG_LEDS_OMAP_PWM)            += leds-omap-pwm.o
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
diff --git a/drivers/leds/leds-omap-pwm.c b/drivers/leds/leds-omap-pwm.c
new file mode 100644 (file)
index 0000000..57eb383
--- /dev/null
@@ -0,0 +1,376 @@
+/* drivers/leds/leds-omap_pwm.c
+ *
+ * Driver to blink LEDs using OMAP PWM timers
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Timo Teras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <asm/delay.h>
+#include <mach/board.h>
+#include <mach/dmtimer.h>
+
+struct omap_pwm_led {
+       struct led_classdev cdev;
+       struct work_struct work;
+       struct omap_pwm_led_platform_data *pdata;
+       struct omap_dm_timer *intensity_timer;
+       struct omap_dm_timer *blink_timer;
+       int powered;
+       unsigned int on_period, off_period;
+       enum led_brightness brightness;
+};
+
+static inline struct omap_pwm_led *pdev_to_omap_pwm_led(struct platform_device *pdev)
+{
+       return platform_get_drvdata(pdev);
+}
+
+static inline struct omap_pwm_led *cdev_to_omap_pwm_led(struct led_classdev *led_cdev)
+{
+       return container_of(led_cdev, struct omap_pwm_led, cdev);
+}
+
+static inline struct omap_pwm_led *work_to_omap_pwm_led(struct work_struct *work)
+{
+       return container_of(work, struct omap_pwm_led, work);
+}
+
+static void omap_pwm_led_set_blink(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+
+       if (led->on_period != 0 && led->off_period != 0) {
+               unsigned long load_reg, cmp_reg;
+
+               load_reg = 32768 * (led->on_period + led->off_period) / 1000;
+               cmp_reg = 32768 * led->on_period / 1000;
+
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_set_load(led->blink_timer, 1, -load_reg);
+               omap_dm_timer_set_match(led->blink_timer, 1, -cmp_reg);
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_write_counter(led->blink_timer, -2);
+               omap_dm_timer_start(led->blink_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->blink_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->blink_timer);
+       }
+}
+
+static void omap_pwm_led_power_on(struct omap_pwm_led *led)
+{
+       if (led->powered)
+               return;
+       led->powered = 1;
+
+       /* Select clock */
+       omap_dm_timer_enable(led->intensity_timer);
+       omap_dm_timer_set_source(led->intensity_timer, OMAP_TIMER_SRC_32_KHZ);
+
+       /* Turn voltage on */
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 1);
+
+       /* Enable PWM timers */
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_enable(led->blink_timer);
+               omap_dm_timer_set_source(led->blink_timer,
+                                        OMAP_TIMER_SRC_32_KHZ);
+               omap_pwm_led_set_blink(led);
+       }
+
+       omap_dm_timer_set_load(led->intensity_timer, 1, 0xffffff00);
+}
+
+static void omap_pwm_led_power_off(struct omap_pwm_led *led)
+{
+       if (!led->powered)
+               return;
+       led->powered = 0;
+
+       /* Everything off */
+       omap_dm_timer_stop(led->intensity_timer);
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (led->blink_timer != NULL) {
+               omap_dm_timer_stop(led->blink_timer);
+               omap_dm_timer_disable(led->blink_timer);
+       }
+
+       if (led->pdata->set_power != NULL)
+               led->pdata->set_power(led->pdata, 0);
+}
+
+static void omap_pwm_led_set_pwm_cycle(struct omap_pwm_led *led, int cycle)
+{
+       int n;
+
+       if (cycle == 0)
+               n = 0xff;
+       else    n = cycle - 1;
+
+       if (cycle == LED_FULL) {
+               omap_dm_timer_set_pwm(led->intensity_timer, 1, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_stop(led->intensity_timer);
+       } else {
+               omap_dm_timer_set_pwm(led->intensity_timer, 0, 1,
+                                     OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+               omap_dm_timer_set_match(led->intensity_timer, 1,
+                                       (0xffffff00) | cycle);
+               omap_dm_timer_start(led->intensity_timer);
+       }
+}
+
+static void omap_pwm_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness value)
+{
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       led->brightness = value;
+       schedule_work(&led->work);
+}
+
+static void omap_pwm_led_work(struct work_struct *work)
+{
+       struct omap_pwm_led *led = work_to_omap_pwm_led(work);
+
+       if (led->brightness != LED_OFF) {
+               omap_pwm_led_power_on(led);
+               omap_pwm_led_set_pwm_cycle(led, led->brightness);
+       } else {
+               omap_pwm_led_power_off(led);
+       }
+}
+
+static ssize_t omap_pwm_led_on_period_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->on_period) + 1;
+}
+
+static ssize_t omap_pwm_led_on_period_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->on_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static ssize_t omap_pwm_led_off_period_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+
+       return sprintf(buf, "%u\n", led->off_period) + 1;
+}
+
+static ssize_t omap_pwm_led_off_period_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t size)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct omap_pwm_led *led = cdev_to_omap_pwm_led(led_cdev);
+       int ret = -EINVAL;
+       unsigned long val;
+       char *after;
+       size_t count;
+
+       val = simple_strtoul(buf, &after, 10);
+       count = after - buf;
+       if (*after && isspace(*after))
+               count++;
+
+       if (count == size) {
+               led->off_period = val;
+               omap_pwm_led_set_blink(led);
+               ret = count;
+       }
+
+       return ret;
+}
+
+static DEVICE_ATTR(on_period, 0644, omap_pwm_led_on_period_show,
+                               omap_pwm_led_on_period_store);
+static DEVICE_ATTR(off_period, 0644, omap_pwm_led_off_period_show,
+                               omap_pwm_led_off_period_store);
+
+static int omap_pwm_led_probe(struct platform_device *pdev)
+{
+       struct omap_pwm_led_platform_data *pdata = pdev->dev.platform_data;
+       struct omap_pwm_led *led;
+       int ret;
+
+       led = kzalloc(sizeof(struct omap_pwm_led), GFP_KERNEL);
+       if (led == NULL) {
+               dev_err(&pdev->dev, "No memory for device\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, led);
+       led->cdev.brightness_set = omap_pwm_led_set;
+       led->cdev.default_trigger = NULL;
+       led->cdev.name = pdata->name;
+       led->pdata = pdata;
+       led->brightness = LED_OFF;
+       INIT_WORK(&led->work, omap_pwm_led_work);
+
+       dev_info(&pdev->dev, "OMAP PWM LED (%s) at GP timer %d/%d\n",
+                pdata->name, pdata->intensity_timer, pdata->blink_timer);
+
+       /* register our new led device */
+       ret = led_classdev_register(&pdev->dev, &led->cdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "led_classdev_register failed\n");
+               goto error_classdev;
+       }
+
+       /* get related dm timers */
+       led->intensity_timer = omap_dm_timer_request_specific(pdata->intensity_timer);
+       if (led->intensity_timer == NULL) {
+               dev_err(&pdev->dev, "failed to request intensity pwm timer\n");
+               ret = -ENODEV;
+               goto error_intensity;
+       }
+       omap_dm_timer_disable(led->intensity_timer);
+
+       if (pdata->blink_timer != 0) {
+               led->blink_timer = omap_dm_timer_request_specific(pdata->blink_timer);
+               if (led->blink_timer == NULL) {
+                       dev_err(&pdev->dev, "failed to request blinking pwm timer\n");
+                       ret = -ENODEV;
+                       goto error_blink1;
+               }
+               omap_dm_timer_disable(led->blink_timer);
+
+               ret = device_create_file(led->cdev.dev,
+                                              &dev_attr_on_period);
+               if(ret)
+                       goto error_blink2;
+
+               ret = device_create_file(led->cdev.dev,
+                                       &dev_attr_off_period);
+               if(ret)
+                       goto error_blink3;
+
+       }
+
+       return 0;
+
+error_blink3:
+       device_remove_file(led->cdev.dev,
+                                &dev_attr_on_period);
+error_blink2:
+       dev_err(&pdev->dev, "failed to create device file(s)\n");
+error_blink1:
+       omap_dm_timer_free(led->intensity_timer);
+error_intensity:
+       led_classdev_unregister(&led->cdev);
+error_classdev:
+       kfree(led);
+       return ret;
+}
+
+static int omap_pwm_led_remove(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       device_remove_file(led->cdev.dev,
+                                &dev_attr_on_period);
+       device_remove_file(led->cdev.dev,
+                                &dev_attr_off_period);
+       led_classdev_unregister(&led->cdev);
+
+       omap_pwm_led_set(&led->cdev, LED_OFF);
+       if (led->blink_timer != NULL)
+               omap_dm_timer_free(led->blink_timer);
+       omap_dm_timer_free(led->intensity_timer);
+       kfree(led);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_pwm_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_suspend(&led->cdev);
+       return 0;
+}
+
+static int omap_pwm_led_resume(struct platform_device *pdev)
+{
+       struct omap_pwm_led *led = pdev_to_omap_pwm_led(pdev);
+
+       led_classdev_resume(&led->cdev);
+       return 0;
+}
+#else
+#define omap_pwm_led_suspend NULL
+#define omap_pwm_led_resume NULL
+#endif
+
+static struct platform_driver omap_pwm_led_driver = {
+       .probe          = omap_pwm_led_probe,
+       .remove         = omap_pwm_led_remove,
+       .suspend        = omap_pwm_led_suspend,
+       .resume         = omap_pwm_led_resume,
+       .driver         = {
+               .name           = "omap_pwm_led",
+               .owner          = THIS_MODULE,
+       },
+};
+
+static int __init omap_pwm_led_init(void)
+{
+       return platform_driver_register(&omap_pwm_led_driver);
+}
+
+static void __exit omap_pwm_led_exit(void)
+{
+       platform_driver_unregister(&omap_pwm_led_driver);
+}
+
+module_init(omap_pwm_led_init);
+module_exit(omap_pwm_led_exit);
+
+MODULE_AUTHOR("Timo Teras");
+MODULE_DESCRIPTION("OMAP PWM LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-omap.c b/drivers/leds/leds-omap.c
new file mode 100644 (file)
index 0000000..5c14c4b
--- /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 <mach/gpio.h>
+#include <mach/hardware.h>
+#include <mach/led.h>
+
+/* our context */
+
+static void omap_set_led_gpio(struct led_classdev *led_cdev,
+                           enum led_brightness value)
+{
+       struct omap_led_config *led_dev;
+
+       led_dev = container_of(led_cdev, struct omap_led_config, cdev);
+
+       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 b23dadeecd0528ad74d55405948562981b24c234..a9e1414cb8a11083ae53cb7b52d34be462b06310 100644 (file)
@@ -101,6 +101,8 @@ struct tea5761_priv {
 
        /* All zero = no test mode */
 
+#define TEA5761_TESTREG_TRIGFR         0x08
+
 /* MANID - Read: bytes 12 and 13 */
 
        /* First byte - should be 0x10 */
@@ -147,20 +149,21 @@ static int set_radio_freq(struct dvb_frontend *fe,
 
        if (params->mode == T_STANDBY) {
                tuner_dbg("TEA5761 set to standby mode\n");
-               buffer[5] |= TEA5761_TNCTRL_MU;
+               buffer[4] |= TEA5761_TNCTRL_MU;
        } else {
-               buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+               buffer[3] |= TEA5761_TNCTRL_PUPD_0;
        }
 
+       buffer[5] = TEA5761_TESTREG_TRIGFR;
 
        if (params->audmode == V4L2_TUNER_MODE_MONO) {
                tuner_dbg("TEA5761 set to mono\n");
-               buffer[5] |= TEA5761_TNCTRL_MST;
+               buffer[4] |= TEA5761_TNCTRL_MST;
        } else {
                tuner_dbg("TEA5761 set to stereo\n");
        }
 
-       div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+       div = (frq * 125 / 2 - 225000) >> 13;
        buffer[1] = (div >> 8) & 0x3f;
        buffer[2] = div & 0xff;
 
@@ -175,6 +178,48 @@ static int set_radio_freq(struct dvb_frontend *fe,
        return 0;
 }
 
+static int tea5761_init(struct dvb_frontend *fe)
+{
+       struct tea5761_priv *priv = fe->tuner_priv;
+       unsigned char buffer[] = {0, 0, 0, 0, 0, 0, 0 };
+       int rc;
+
+       tuner_dbg("Power up radio\n");
+
+       buffer[3] = TEA5761_TNCTRL_PUPD_0;
+
+       if (debug)
+               tea5761_status_dump(buffer);
+
+       rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, ARRAY_SIZE(buffer));
+       if (rc != ARRAY_SIZE(buffer))
+               tuner_warn("i2c i/o error: rc == %d (should be %d)\n", rc,
+                               ARRAY_SIZE(buffer));
+
+       return 0;
+}
+
+static int tea5761_sleep(struct dvb_frontend *fe)
+{
+       struct tea5761_priv *priv = fe->tuner_priv;
+       unsigned char buffer[] = {0, 0, 0, 0, 0, 0, 0 };
+       int rc;
+
+       tuner_dbg("Power down radio\n");
+
+       buffer[3] &= ~TEA5761_TNCTRL_PUPD_0;
+
+       if (debug)
+               tea5761_status_dump(buffer);
+
+       rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, ARRAY_SIZE(buffer));
+       if (rc != ARRAY_SIZE(buffer))
+               tuner_warn("i2c i/o error: rc == %d (should be %d)\n", rc,
+                               ARRAY_SIZE(buffer));
+
+       return 0;
+}
+
 static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
 {
        struct tea5761_priv *priv = fe->tuner_priv;
@@ -287,6 +332,8 @@ static struct dvb_tuner_ops tea5761_tuner_ops = {
        .get_frequency     = tea5761_get_frequency,
        .get_status        = tea5761_get_status,
        .get_rf_strength   = tea5761_get_rf_strength,
+       .init              = tea5761_init,
+       .sleep             = tea5761_sleep,
 };
 
 struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
index 1b41b3f77cf95c2b6f28394cf1eb378a2fefe0ec..de6ca277dabf143a0f790799813ff1a56d5e6c3a 100644 (file)
@@ -339,6 +339,19 @@ config RADIO_ZOLTRIX_PORT
        help
          Enter the I/O port of your Zoltrix radio card.
 
+config RADIO_TEA5761
+       tristate "Philips Semiconductors TEA5761 I2C FM Radio"
+       help
+         Choose Y here if you have one of these AM/FM radio cards.
+
+         In order to control your radio card, you will need to use programs
+         that are compatible with the Video For Linux 2 API.  Information on
+         this API and pointers to "v4l" programs may be found at
+         <file:Documentation/video4linux/API.html>.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-tea5761.
+
 config USB_DSBR
        tristate "D-Link/GemTek USB FM radio support"
        depends on USB && VIDEO_V4L2
index 7ca71ab96b43021d5edd3080f118b7fe2f072f44..645ab0b49d7b2fe49d51083ce8b6343baea1a72a 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_RADIO_TEA5761) += radio-tea5761.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_USB_SI470X) += radio-si470x.o
 
diff --git a/drivers/media/radio/radio-tea5761.c b/drivers/media/radio/radio-tea5761.c
new file mode 100644 (file)
index 0000000..1c6d8ab
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * drivers/media/radio/radio-tea5761.c
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#define DRIVER_NAME "tea5761"
+
+#define TEA5761_VERSION                KERNEL_VERSION(0, 0, 1)
+
+#define TEA5761_I2C_ADDR       0x10
+
+#define TEA5761_MANID          0x002b
+#define TEA5761_CHIPID         0x5761
+
+#define TEA5761_INTREG_BLMSK   0x0001
+#define TEA5761_INTREG_FRRMSK  0x0002
+#define TEA5761_INTREG_LEVMSK  0x0008
+#define TEA5761_INTREG_IFMSK   0x0010
+#define TEA5761_INTREG_BLMFLAG 0x0100
+#define TEA5761_INTREG_FRRFLAG 0x0200
+#define TEA5761_INTREG_LEVFLAG 0x0800
+#define TEA5761_INTREG_IFFLAG  0x1000
+
+#define TEA5761_FRQSET_SUD     0x8000
+#define TEA5761_FRQSET_SM      0x4000
+
+#define TEA5761_TNCTRL_PUPD0   0x4000
+#define TEA5761_TNCTRL_BLIM    0x2000
+#define TEA5761_TNCTRL_SWPM    0x1000
+#define TEA5761_TNCTRL_IFCTC   0x0800
+#define TEA5761_TNCTRL_AFM     0x0400
+#define TEA5761_TNCTRL_SMUTE   0x0200
+#define TEA5761_TNCTRL_SNC     0x0100
+#define TEA5761_TNCTRL_MU      0x0080
+#define TEA5761_TNCTRL_SSL1    0x0040
+#define TEA5761_TNCTRL_SSL0    0x0020
+#define TEA5761_TNCTRL_HLSI    0x0010
+#define TEA5761_TNCTRL_MST     0x0008
+#define TEA5761_TNCTRL_SWP     0x0004
+#define TEA5761_TNCTRL_DTC     0x0002
+#define TEA5761_TNCTRL_AHLSI   0x0001
+
+#define TEA5761_TUNCHK_LEVEL(x)        (((x) & 0x00F0) >> 4)
+#define TEA5761_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
+#define TEA5761_TUNCHK_TUNTO   0x0100
+#define TEA5761_TUNCHK_LD      0x0008
+#define TEA5761_TUNCHK_STEREO  0x0004
+
+#define TEA5761_TESTREG_TRIGFR 0x0800
+
+#define TEA5761_FREQ_LOW       87500
+#define TEA5761_FREQ_HIGH      108000
+
+struct tea5761_regs {
+       u16 intreg;
+       u16 frqset;
+       u16 tnctrl;
+       u16 frqchk;
+       u16 tunchk;
+       u16 testreg;
+       u16 manid;
+       u16 chipid;
+} __attribute__ ((packed));
+
+struct tea5761_write_regs {
+       u8 intreg;
+       u16 frqset;
+       u16 tnctrl;
+       u16 testreg;
+} __attribute__ ((packed));
+
+struct tea5761_device {
+       struct video_device     *video_dev;
+       struct i2c_client       *i2c_dev;
+       struct tea5761_regs     regs;
+       struct mutex            mutex;
+       int                     users;
+};
+
+static struct tea5761_device tea5761;
+
+static struct i2c_driver       tea5761_driver;
+static int radio_nr = -1;
+
+static int tea5761_read_regs(struct tea5761_device *tea)
+{
+       int rc, i;
+       u16 *p = (u16 *) &tea->regs;
+       struct i2c_client *client = tea->i2c_dev;
+
+       rc = i2c_master_recv(client, (void*) &tea->regs, sizeof(tea->regs));
+       for (i = 0; i < 8; i++) {
+               p[i] = __be16_to_cpu(p[i]);
+       }
+
+       dev_dbg(&client->dev,
+               "chip state: %04x %04x %04x %04x %04x %04x %04x %04x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+
+       if (rc < 0)
+               dev_err(&client->dev, "read\n");
+
+       return rc;
+}
+
+static void tea5761_write_regs(struct tea5761_device *tea)
+{
+       struct tea5761_write_regs wr;
+       struct tea5761_regs *r = &tea->regs;
+       struct i2c_client *client = tea->i2c_dev;
+       u8 *p = (u8 *) r;
+
+       wr.intreg = r->intreg & 0xff;
+       wr.frqset = __cpu_to_be16(r->frqset);
+       wr.tnctrl = __cpu_to_be16(r->tnctrl);
+       wr.testreg = __cpu_to_be16(r->testreg);
+
+       dev_dbg(&client->dev,
+               "writing state: %02x %02x %02x %02x %02x %02x %02x\n",
+               p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
+       if (i2c_master_send(client, (void *) &wr, sizeof(wr)) < 0)
+               dev_err(&client->dev, "write\n");
+}
+
+static void tea5761_power_up(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (!(r->tnctrl & TEA5761_TNCTRL_PUPD0)) {
+               r->tnctrl &= ~(TEA5761_TNCTRL_AFM | TEA5761_TNCTRL_MU |
+                              TEA5761_TNCTRL_HLSI);
+               r->testreg |= TEA5761_TESTREG_TRIGFR;
+               r->tnctrl |= TEA5761_TNCTRL_PUPD0;
+               return tea5761_write_regs(tea);
+       }
+}
+
+static void tea5761_power_down(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_PUPD0) {
+               r->tnctrl &= ~TEA5761_TNCTRL_PUPD0;
+               return tea5761_write_regs(tea);
+       }
+}
+
+static void tea5761_set_freq(struct tea5761_device *tea, int freq)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+               r->frqset = (freq + 225000) / 8192;
+       else
+               r->frqset = (freq - 225000) / 8192;
+}
+
+static int tea5761_get_freq(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_HLSI)
+               return (r->frqchk * 8192) - 225000;
+       else
+               return (r->frqchk * 8192) + 225000;
+}
+
+static void tea5761_tune(struct tea5761_device *tea, int freq)
+{
+       tea5761_set_freq(tea, freq);
+       tea5761_write_regs(tea);
+}
+
+static void tea5761_set_audout_mode(struct tea5761_device *tea, int audmode)
+{
+       struct tea5761_regs *r = &tea->regs;
+       int tnctrl = r->tnctrl;
+
+       if (audmode == V4L2_TUNER_MODE_MONO)
+               r->tnctrl |= TEA5761_TNCTRL_MST;
+       else
+               r->tnctrl &= ~TEA5761_TNCTRL_MST;
+       if (tnctrl != r->tnctrl)
+               tea5761_write_regs(tea);
+}
+
+static int tea5761_get_audout_mode(struct tea5761_device *tea)
+{
+       struct tea5761_regs *r = &tea->regs;
+
+       if (r->tnctrl & TEA5761_TNCTRL_MST)
+               return V4L2_TUNER_MODE_MONO;
+       else
+               return V4L2_TUNER_MODE_STEREO;
+}
+
+static void tea5761_mute(struct tea5761_device *tea, int on)
+{
+       struct tea5761_regs *r = &tea->regs;
+       int tnctrl = r->tnctrl;
+
+       if (on)
+               r->tnctrl |= TEA5761_TNCTRL_MU;
+       else
+               r->tnctrl &= ~TEA5761_TNCTRL_MU;
+       if (tnctrl != r->tnctrl)
+               tea5761_write_regs(tea);
+}
+
+static int tea5761_is_muted(struct tea5761_device *tea)
+{
+       return tea->regs.tnctrl & TEA5761_TNCTRL_MU;
+}
+
+static int tea5761_do_ioctl(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct tea5761_device *tea = file->private_data;
+       struct video_device *dev = tea->video_dev;
+       struct i2c_client *client = tea->i2c_dev;
+       struct tea5761_regs *r = &tea->regs;
+
+       union {
+               struct v4l2_capability c;
+               struct v4l2_tuner t;
+               struct v4l2_frequency f;
+               struct v4l2_queryctrl qc;
+               struct v4l2_control ct;
+       } *u = arg;
+
+       tea5761_read_regs(tea);
+
+       switch (cmd) {
+       case VIDIOC_QUERYCAP:
+               dev_dbg(&client->dev, "VIDIOC_QUERYCAP\n");
+               memset(&u->c, 0, sizeof(u->c));
+               strlcpy(u->c.driver,
+                       dev->parent->driver->name,
+                       sizeof(u->c.driver));
+               strlcpy(u->c.card, dev->name, sizeof(u->c.card));
+               snprintf(u->c.bus_info, sizeof(u->c.bus_info), "I2C:%s",
+                        dev->parent->bus_id);
+               u->c.version = TEA5761_VERSION;
+               u->c.capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+               break;
+
+       case VIDIOC_G_TUNER:
+               /* Only one tuner chip */
+               dev_dbg(&client->dev, "VIDIOC_G_TUNER\n");
+               if (u->t.index != 0)
+                       return -EINVAL;
+
+               memset(&u->t, 0, sizeof(u->t));
+               u->t.type = V4L2_TUNER_RADIO;
+               strlcpy(u->t.name, "FM", sizeof(u->t.name));
+               /* Freq in 62.5Hz units */
+               u->t.rangelow = TEA5761_FREQ_LOW * 16;
+               u->t.rangehigh = TEA5761_FREQ_HIGH * 16;
+               u->t.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+               if (r->tunchk & TEA5761_TUNCHK_STEREO)
+                       u->t.rxsubchans = V4L2_TUNER_SUB_STEREO;
+               u->t.audmode = tea5761_get_audout_mode(tea);
+               u->t.signal = TEA5761_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
+               u->t.afc = TEA5761_TUNCHK_IFCNT(r->tunchk);
+               break;
+
+       case VIDIOC_S_TUNER:
+               /* Only tuner nro 0 can be selected. */
+               dev_dbg(&client->dev, "VIDIOC_S_TUNER\n");
+               if (u->t.index != 0)
+                       return -EINVAL;
+               tea5761_set_audout_mode(tea, u->t.audmode);
+               break;
+
+       case VIDIOC_G_FREQUENCY:
+               dev_dbg(&client->dev, "VIDIOC_G_FREQUENCY\n");
+               memset(&u->f, 0, sizeof(u->f));
+               u->f.type = V4L2_TUNER_RADIO;
+               if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+                       u->f.frequency = (tea5761_get_freq(tea) * 2) / 125;
+               else
+                       u->f.frequency = 0;
+               break;
+
+       case VIDIOC_S_FREQUENCY:
+               dev_dbg(&client->dev, "VIDIOC_S_FREQUENCY %u\n",
+                       u->f.frequency);
+               if (u->f.tuner != 0)
+                       return -EINVAL;
+               if (u->f.frequency == 0) {
+                       /* We special case this as a power down
+                        * control. */
+                       tea5761_power_down(tea);
+                       break;
+               }
+               if (u->f.frequency < 16 * TEA5761_FREQ_LOW)
+                       return -EINVAL;
+               if (u->f.frequency > 16 * TEA5761_FREQ_HIGH)
+                       return -EINVAL;
+
+               tea5761_power_up(tea);
+               tea5761_tune(tea, (u->f.frequency * 125) / 2);
+               break;
+
+       case VIDIOC_QUERYCTRL:
+               dev_dbg(&client->dev, "VIDIOC_QUERYCTRL %d\n", u->qc.id);
+               if (u->qc.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               strlcpy(u->qc.name, "Mute", sizeof(u->qc.name));
+               u->qc.minimum = 0;
+               u->qc.maximum = 1;
+               u->qc.step = 1;
+               u->qc.default_value = 0;
+               u->qc.type = V4L2_CTRL_TYPE_BOOLEAN;
+               break;
+
+       case VIDIOC_G_CTRL:
+               dev_dbg(&client->dev, "VIDIOC_G_CTRL %d\n", u->ct.id);
+               if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               if (r->tnctrl & TEA5761_TNCTRL_PUPD0)
+                       u->ct.value = tea5761_is_muted(tea) ? 1 : 0;
+               else
+                       u->ct.value = 0;
+               break;
+
+       case VIDIOC_S_CTRL:
+               dev_dbg(&client->dev, "VIDIOC_S_CTRL %d\n", u->ct.id);
+               if (u->ct.id != V4L2_CID_AUDIO_MUTE)
+                       return -EINVAL;
+               tea5761_mute(tea, u->ct.value);
+               break;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+
+       return 0;
+}
+
+static int tea5761_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       return video_usercopy(inode, file, cmd, arg, tea5761_do_ioctl);
+}
+
+static int tea5761_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(file->f_dentry->d_inode);
+       /* Currently we support only one device */
+       struct tea5761_device *tea = &tea5761;
+
+       if (tea->video_dev->minor != minor)
+               return -ENODEV;
+
+       mutex_lock(&tea->mutex);
+       /* Only exclusive access */
+       if (tea->users) {
+               mutex_unlock(&tea->mutex);
+               return -EBUSY;
+       }
+       tea->users++;
+       mutex_unlock(&tea->mutex);
+
+       file->private_data = tea;
+       return 0;
+}
+
+static int tea5761_release(struct inode *inode, struct file *file)
+{
+       struct tea5761_device *tea = file->private_data;
+
+       mutex_lock(&tea->mutex);
+       tea->users--;
+       mutex_unlock(&tea->mutex);
+
+       return 0;
+}
+
+static struct file_operations tea5761_fops = {
+       .owner          = THIS_MODULE,
+       .open           = tea5761_open,
+       .release        = tea5761_release,
+       .ioctl          = tea5761_ioctl,
+       .llseek         = no_llseek,
+};
+
+static struct video_device tea5761_video_device = {
+       .name          = "TEA5761 FM-Radio",
+       .vfl_type      = VID_TYPE_TUNER,
+       .fops          = &tea5761_fops,
+       .release       = video_device_release
+};
+
+static int tea5761_i2c_driver_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct video_device *video_dev;
+       int err = 0;
+       struct tea5761_device *tea = &tea5761;
+
+       mutex_init(&tea->mutex);
+
+       tea->i2c_dev = client;
+
+       /* V4L initialization */
+       video_dev = video_device_alloc();
+       if (video_dev == NULL) {
+               dev_err(&client->dev, "couldn't allocate memory\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+       tea->video_dev = video_dev;
+
+       *video_dev = tea5761_video_device;
+       video_dev->parent = &client->dev;
+       i2c_set_clientdata(client, video_dev);
+
+       /* initialize and power off the chip */
+       tea5761_read_regs(tea);
+       tea5761_set_audout_mode(tea, V4L2_TUNER_MODE_STEREO);
+       tea5761_mute(tea, 0);
+       tea5761_power_down(tea);
+
+       tea5761.video_dev = video_dev;
+       tea5761.i2c_dev = client;
+
+       err = video_register_device(video_dev, VFL_TYPE_RADIO, radio_nr);
+       if (err) {
+               dev_err(&client->dev, "couldn't register video device\n");
+               goto err_video_alloc;
+       }
+
+       dev_info(&client->dev, "tea5761 (version %d) detected\n",
+               (tea->regs.manid >> 12) & 0xf);
+
+       return 0;
+
+err_video_alloc:
+       video_device_release(video_dev);
+exit:
+       kfree(client);
+       return err;
+}
+
+static int tea5761_i2c_driver_remove(struct i2c_client *client)
+{
+       struct video_device *vd = i2c_get_clientdata(client);
+
+       video_unregister_device(vd);
+
+       return 0;
+}
+
+static const struct i2c_device_id tea5761_id[] = {
+       { DRIVER_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, tea5761_id);
+
+static struct i2c_driver tea5761_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+       },
+       .probe  = tea5761_i2c_driver_probe,
+       .remove = __devexit_p(tea5761_i2c_driver_remove),
+       .id_table = tea5761_id,
+};
+
+static int __init tea5761_init(void)
+{
+       int res;
+
+       if ((res = i2c_add_driver(&tea5761_driver))) {
+               printk(KERN_ERR DRIVER_NAME ": driver registration failed\n");
+               return res;
+       }
+
+       return 0;
+}
+
+static void __exit tea5761_exit(void)
+{
+       i2c_del_driver(&tea5761_driver);
+}
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("I2C interface for TEA5761.");
+MODULE_LICENSE("GPL");
+
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
+
+module_init(tea5761_init)
+module_exit(tea5761_exit)
index 3e9e0dcd217ecfaf278cdef11f6cb8cb18f666a2..f914577ea426800f5ec77bbf23f278f6a8035756 100644 (file)
@@ -295,6 +295,14 @@ config VIDEO_TCM825X
          This is a driver for the Toshiba TCM825x VGA camera sensor.
          It is used for example in Nokia N800.
 
+config VIDEO_OV9640
+       tristate "OmniVision OV9640 sensor support"
+       depends on I2C && VIDEO_V4L2
+       ---help---
+         This is a Video4Linux2 sensor-level driver for the OmniVision
+         OV9640 camera.  It is currently working with the TI OMAP2
+         camera controller.
+
 config VIDEO_SAA7110
        tristate "Philips SAA7110 video decoder"
        depends on VIDEO_V4L1 && I2C
@@ -754,6 +762,8 @@ source "drivers/media/video/au0828/Kconfig"
 
 source "drivers/media/video/ivtv/Kconfig"
 
+source drivers/media/video/omap/Kconfig
+
 source "drivers/media/video/cx18/Kconfig"
 
 config VIDEO_M32R_AR
@@ -784,6 +794,15 @@ config VIDEO_CAFE_CCIC
          CMOS camera controller.  This is the controller found on first-
          generation OLPC systems.
 
+config VIDEO_OMAP2
+       tristate "OMAP 2 Camera support (EXPERIMENTAL)"
+       select VIDEOBUF_GEN
+       select VIDEOBUF_DMA_SG
+       depends on VIDEO_V4L2 && ARCH_OMAP24XX
+       ---help---
+         Driver for an OMAP 2 camera controller.
+
+
 #
 # USB Multimedia device configuration
 #
index ef7c8d3ffb18bba4e3930668285a30883fc1fc10..3e580e80e4b32a93467f7b0a05716c89469e15f3 100644 (file)
@@ -96,6 +96,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
@@ -105,7 +106,9 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
 
+obj-$(CONFIG_VIDEO_OMAP2) += omap24xxcam.o omap24xxcam-dma.o
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_OV9640)     += ov9640.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644 (file)
index 0000000..c8d1f4c
--- /dev/null
@@ -0,0 +1,7 @@
+config VIDEO_OMAP_CAMERA
+       tristate "OMAP Camera support (EXPERIMENTAL)"
+       select VIDEOBUF_GEN
+       select VIDEOBUF_DMA_SG
+       depends on VIDEO_DEV && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+       help
+         V4L2 camera driver support for OMAP1/2 based boards.
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644 (file)
index 0000000..9b4a998
--- /dev/null
@@ -0,0 +1,9 @@
+# Makefile for OMAP1/2 camera driver
+
+obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omapcamera.o
+
+objs-y$(CONFIG_ARCH_OMAP16XX) += omap16xxcam.o camera_core.o
+
+omapcamera-objs := $(objs-yy)
+
+EXTRA_CFLAGS = -I$(src)/..
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..eeedb36
--- /dev/null
@@ -0,0 +1,1280 @@
+/*
+ * drivers/media/video/omap/camera_core.c
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP H2 and H3 camera controller.
+ *
+ * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com)
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *   27/03/05   Vladimir Barinov - Added support for power management
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+
+#include <media/v4l2-common.h>
+
+#include <asm/io.h>
+
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define OMAP1CAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+static struct camera_device *camera_dev;
+static void camera_core_sgdma_process(struct camera_device *cam);
+
+/* Module parameters */
+static int video_nr = -1;      /* Video device minor (-1 ==> auto assign) */
+
+/* Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+/* Size of video overlay framebuffer. This determines the maximum image size
+ * that can be previewed. Default is 600KB, enough for sxga.
+ */
+static int overlay_mem = 640 * 480 * 2;
+
+/* Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable do not need to be balanced.
+ */
+static int camera_sensor_if_enable(struct camera_device *cam)
+{
+       int rval;
+       struct v4l2_ifparm p;
+
+       rval = vidioc_int_g_ifparm(cam->sdev, &p);
+       if (rval) {
+               dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+               return rval;
+       }
+
+       cam->if_type = p.if_type;
+
+       switch (p.if_type) {
+       case V4L2_IF_TYPE_BT656:
+               cam->if_u.bt656.xclk =
+                   cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+                                               cam->hardware_data);
+               break;
+       default:
+               /* FIXME: how about other interfaces? */
+               dev_err(cam->dev, "interface type %d not supported\n",
+                       p.if_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void camera_sensor_if_disable(const struct camera_device *cam)
+{
+       switch (cam->if_type) {
+       case V4L2_IF_TYPE_BT656:
+               break;
+       }
+}
+
+/* Initialize the sensor hardware. */
+static int camera_sensor_init(struct camera_device *cam)
+{
+       int err = 0;
+       struct v4l2_int_device *sdev = cam->sdev;
+
+       /* Enable the xclk output.  The sensor may (and does, in the case of
+        * the OV9640) require an xclk input in order for its initialization
+        * routine to work.
+        */
+
+       /* Choose an arbitrary xclk frequency */
+       cam->if_u.bt656.xclk = 21000000;
+
+       cam->if_u.bt656.xclk = cam->cam_hardware->set_xclk(cam->if_u.bt656.xclk,
+                                                          cam->hardware_data);
+
+       err = camera_sensor_if_enable(cam);
+       if (err) {
+               dev_err(cam->dev, "sensor interface could not be enabled at "
+                       "initialization, %d\n", err);
+               cam->sdev = NULL;
+               goto out;
+       }
+
+       /* Power up sensor during sensor initialization */
+       vidioc_int_s_power(sdev, 1);
+
+       err = vidioc_int_dev_init(sdev);
+       if (err) {
+               dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+               /* Sensor initialization failed --- it's nonexistent to us! */
+               cam->sdev = NULL;
+               goto out;
+       }
+
+       dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+       camera_sensor_if_disable(cam);
+
+       vidioc_int_s_power(sdev, 0);
+
+       return err;
+}
+
+static void camera_sensor_exit(struct camera_device *cam)
+{
+       if (cam->sdev)
+               vidioc_int_dev_exit(cam->sdev);
+}
+
+/* DMA completion routine for the scatter-gather DMA fragments.
+ * This function is called when a scatter DMA fragment is completed
+ */
+static void camera_core_callback_sgdma(void *arg1, void *arg2)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int sgslot = (int)arg2;
+
+       struct sgdma_state *sgdma;
+
+       spin_lock(&cam->sg_lock);
+       sgdma = cam->sgdma + sgslot;
+       if (!sgdma->queued_sglist) {
+               spin_unlock(&cam->sg_lock);
+               dev_err(cam->dev, "SGDMA completed when none queued\n");
+               return;
+       }
+       if (!--sgdma->queued_sglist) {
+               /* Queue for this sglist is empty so check whether transfer
+                * of the frame has been completed
+                */
+               if (sgdma->next_sglist == sgdma->sglen) {
+                       dma_callback_t callback = sgdma->callback;
+                       void *arg = sgdma->arg;
+                       /* All done with this sglist */
+                       cam->free_sgdma++;
+                       if (callback) {
+                               spin_unlock(&cam->sg_lock);
+                               (*callback) (cam, arg);
+                               camera_core_sgdma_process(cam);
+                               return;
+                       }
+               }
+       }
+       spin_unlock(&cam->sg_lock);
+       camera_core_sgdma_process(cam);
+
+       return;
+}
+
+static void camera_core_sgdma_init(struct camera_device *cam)
+{
+       int sg;
+
+       /* Initialize the underlying camera DMA */
+       cam->cam_hardware->init_dma(cam->hardware_data);
+       spin_lock_init(&cam->sg_lock);
+
+       cam->free_sgdma = NUM_SG_DMA;
+       cam->next_sgdma = 0;
+       for (sg = 0; sg < NUM_SG_DMA; sg++) {
+               cam->sgdma[sg].sglen = 0;
+               cam->sgdma[sg].next_sglist = 0;
+               cam->sgdma[sg].queued_sglist = 0;
+               cam->sgdma[sg].csr = 0;
+               cam->sgdma[sg].callback = NULL;
+               cam->sgdma[sg].arg = NULL;
+       }
+}
+
+/* Process the scatter-gather DMA queue by starting queued transfers
+ * This function is called to program the DMA to start the transfer of an image.
+ */
+static void camera_core_sgdma_process(struct camera_device *cam)
+{
+       unsigned long irqflags;
+       int queued_sgdma, sgslot;
+       struct sgdma_state *sgdma;
+       const struct scatterlist *sglist;
+
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+       if (1 == cam->in_use) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return;
+       }
+       cam->in_use = 1;
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       queued_sgdma = NUM_SG_DMA - cam->free_sgdma;
+       sgslot = (cam->next_sgdma + cam->free_sgdma) % (NUM_SG_DMA);
+       while (queued_sgdma > 0) {
+               sgdma = cam->sgdma + sgslot;
+               while (sgdma->next_sglist < sgdma->sglen) {
+                       sglist = sgdma->sglist + sgdma->next_sglist;
+                       if (cam->cam_hardware->
+                           start_dma(sgdma, camera_core_callback_sgdma,
+                                     (void *)cam, (void *)sgslot,
+                                     cam->hardware_data)) {
+                               /* DMA start failed */
+                               cam->in_use = 0;
+                               return;
+                       } else {
+                               /* DMA start successful */
+                               sgdma->next_sglist++;
+                               sgdma->queued_sglist++;
+                       }
+               }
+               queued_sgdma--;
+               sgslot = (sgslot + 1) % (NUM_SG_DMA);
+       }
+
+       cam->in_use = 0;
+}
+
+/* Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or
+ * non-zero if all of the scatter-gather slots are already in use.
+ */
+static int camera_core_sgdma_queue(struct camera_device *cam,
+                                  const struct scatterlist *sglist,
+                                  int sglen, dma_callback_t callback,
+                                  void *arg)
+{
+       unsigned long irqflags;
+       struct sgdma_state *sgdma;
+
+       if ((sglen < 0) || ((sglen > 0) & !sglist))
+               return -EINVAL;
+
+       spin_lock_irqsave(&cam->sg_lock, irqflags);
+
+       if (!cam->free_sgdma) {
+               spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+               return -EBUSY;
+       }
+
+       sgdma = cam->sgdma + cam->next_sgdma;
+
+       sgdma->sglist = sglist;
+       sgdma->sglen = sglen;
+       sgdma->next_sglist = 0;
+       sgdma->queued_sglist = 0;
+       sgdma->csr = 0;
+       sgdma->callback = callback;
+       sgdma->arg = arg;
+
+       cam->next_sgdma = (cam->next_sgdma + 1) % (NUM_SG_DMA);
+       cam->free_sgdma--;
+
+       spin_unlock_irqrestore(&cam->sg_lock, irqflags);
+
+       camera_core_sgdma_process(cam);
+
+       return 0;
+}
+
+/* -------------------overlay routines ------------------------------
+ * Callback routine for overlay DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+static void camera_core_overlay_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       int i, j;
+       int count, index;
+       unsigned char *fb_buf =
+           phys_to_virt((unsigned long)camera_dev->fbuf.base);
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       if (!cam->previewing || cam->overlay_cnt == 0) {
+               spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+               return;
+       }
+
+       --cam->overlay_cnt;
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+
+       count = 0;
+       j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline);
+       for (i = 0; i < cam->pix.sizeimage; i += cam->pix.bytesperline) {
+               for (index = 0; index < cam->pix.bytesperline; index++) {
+                       fb_buf[j] = *(((unsigned char *)cam->overlay_base) +
+                                     i + index);
+                       index++;
+                       fb_buf[j + 1] =
+                           *(((unsigned char *)cam->overlay_base) + i + index);
+                       j = j - cam->fbuf.fmt.bytesperline;
+               }
+               count += 2;
+               j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count;
+       }
+
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                                             camera_core_overlay_callback,
+                                             NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+
+}
+
+static void camera_core_start_overlay(struct camera_device *cam)
+{
+       int err;
+       unsigned long irqflags;
+
+       if (!cam->previewing)
+               return;
+
+       spin_lock_irqsave(&cam->overlay_lock, irqflags);
+
+       sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys;
+       sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage;
+       while (cam->overlay_cnt < 2) {
+               err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1,
+                                             camera_core_overlay_callback,
+                                             NULL);
+               if (err)
+                       break;
+               ++cam->overlay_cnt;
+       }
+
+       spin_unlock_irqrestore(&cam->overlay_lock, irqflags);
+}
+
+/* ------------------ videobuf_queue_ops --------------------------------
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void camera_core_vbq_complete(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+
+       spin_lock(&cam->vbq_lock);
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = cam->field_count;
+       cam->field_count += 2;
+       vb->state = STATE_DONE;
+
+       wake_up(&vb->done);
+
+       spin_unlock(&cam->vbq_lock);
+}
+
+static void camera_core_vbq_release(struct videobuf_queue *q,
+                                   struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+       videobuf_waiton(vb, 0, 0);
+       videobuf_dma_unmap(q, dma);
+       videobuf_dma_free(dma);
+
+       vb->state = STATE_NEEDS_INIT;
+}
+
+/* Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int camera_core_vbq_setup(struct videobuf_queue *q, unsigned int *cnt,
+                                unsigned int *size)
+{
+       struct camera_fh *fh = q->priv_data;
+       struct camera_device *cam = fh->cam;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* Supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       spin_lock(&cam->img_lock);
+       *size = cam->pix.sizeimage;
+       spin_unlock(&cam->img_lock);
+
+       while (*size * *cnt > capture_mem)
+               (*cnt)--;
+
+       return 0;
+}
+
+static int camera_core_vbq_prepare(struct videobuf_queue *q,
+                                  struct videobuf_buffer *vb,
+                                  enum v4l2_field field)
+{
+       struct camera_fh *fh = q->priv_data;
+       struct camera_device *cam = fh->cam;
+       int err = 0;
+
+       spin_lock(&cam->img_lock);
+       if (cam->pix.sizeimage > vb->bsize) {
+               spin_unlock(&cam->img_lock);
+               return -EINVAL;
+       }
+       vb->size = cam->pix.sizeimage;
+       vb->width = cam->pix.width;
+       vb->height = cam->pix.height;
+       vb->field = field;
+       spin_unlock(&cam->img_lock);
+
+       if (vb->state == STATE_NEEDS_INIT)
+               err = videobuf_iolock(q, vb, NULL);
+
+       if (!err)
+               vb->state = STATE_PREPARED;
+       else
+               camera_core_vbq_release(q, vb);
+
+       return err;
+}
+
+static void camera_core_vbq_queue(struct videobuf_queue *q,
+                                 struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+       struct camera_fh *fh = q->priv_data;
+       struct camera_device *cam = fh->cam;
+       enum videobuf_state state = vb->state;
+       int err;
+
+       vb->state = STATE_QUEUED;
+       err = camera_core_sgdma_queue(cam, dma->sglist, dma->sglen,
+                                     camera_core_vbq_complete, vb);
+       if (err) {
+               /* Oops.  We're not supposed to get any errors here.  The only
+                * way we could get an error is if we ran out of scatter-gather
+                * DMA slots, but we are supposed to have at least as many
+                * scatter-gather DMA slots as video buffers so that can't
+                * happen.
+                */
+               dev_dbg(cam->dev, "Failed to queue a video buffer for SGDMA\n");
+               vb->state = state;
+       }
+}
+
+/* IOCTL interface. */
+static int vidioc_querycap(struct file *file, void *fh,
+                          struct v4l2_capability *cap)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+       cap->version = OMAP1CAM_VERSION;
+       cap->capabilities =
+           V4L2_CAP_VIDEO_CAPTURE |
+           V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+                              struct v4l2_fmtdesc *f)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       return vidioc_int_enum_fmt_cap(cam->sdev, f);
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       /* Get the current format */
+       memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
+       f->fmt.pix = cam->pix;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+       int rval = 0;
+
+       vidioc_int_try_fmt_cap(cam->sdev, f);
+
+       cam->pix = f->fmt.pix;
+
+       rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+       camera_sensor_if_enable(cam);
+
+       return rval;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+                             struct v4l2_format *f)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       return vidioc_int_try_fmt_cap(cam->sdev, f);
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+                         struct v4l2_requestbuffers *b)
+{
+       struct camera_fh *ofh = fh;
+
+       return videobuf_reqbufs(&ofh->vbq, b);
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct camera_fh *ofh = fh;
+
+       return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct camera_fh *ofh = fh;
+
+       return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct camera_fh *ofh = fh;
+
+       return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       spin_lock(&cam->img_lock);
+
+       if (cam->streaming || cam->reading) {
+               spin_unlock(&cam->img_lock);
+               return -EBUSY;
+       } else
+               cam->streaming = ofh;
+       /* FIXME: start camera interface */
+
+       spin_unlock(&cam->img_lock);
+
+       return videobuf_streamon(&ofh->vbq);
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+       int err;
+
+       err = videobuf_streamoff(&ofh->vbq);
+       if (err < 0)
+               return err;
+
+       spin_lock(&cam->img_lock);
+       if (cam->streaming == ofh)
+               cam->streaming = NULL;
+       /* FIXME: stop camera interface */
+
+       spin_unlock(&cam->img_lock);
+       return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index > 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+                           struct v4l2_queryctrl *a)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       return vidioc_int_queryctrl(cam->sdev, a);
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       return vidioc_int_g_ctrl(cam->sdev, a);
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       return vidioc_int_s_ctrl(cam->sdev, a);
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+                        struct v4l2_framebuffer *a)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       spin_lock(&cam->img_lock);
+       *a = cam->fbuf;
+       spin_unlock(&cam->img_lock);
+
+       return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+                        struct v4l2_framebuffer *a)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+
+       spin_lock(&cam->img_lock);
+       if (cam->previewing) {
+               spin_unlock(&cam->img_lock);
+               return -EBUSY;
+       }
+       cam->fbuf.base = a->base;
+       cam->fbuf.fmt = a->fmt;
+
+       spin_unlock(&cam->img_lock);
+       return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *fh, unsigned int i)
+{
+       struct camera_fh *ofh = fh;
+       struct camera_device *cam = ofh->cam;
+       int enable = i;
+
+       /* Check whether the capture format and
+        * the display format matches
+        * return failure if they are different
+        */
+       if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat)
+               return -EINVAL;
+
+       /* If the camera image size is greater
+        * than LCD size return failure
+        */
+       if ((cam->pix.width > cam->fbuf.fmt.height) ||
+           (cam->pix.height > cam->fbuf.fmt.width))
+               return -EINVAL;
+
+       if (!cam->previewing && enable) {
+               cam->previewing = fh;
+               cam->overlay_cnt = 0;
+               camera_core_start_overlay(cam);
+       } else if (!enable)
+               cam->previewing = NULL;
+
+       return 0;
+}
+
+/* File operations */
+static unsigned int camera_core_poll(struct file *file,
+                                    struct poll_table_struct *wait)
+{
+       return -EINVAL;
+}
+
+/* Callback routine for read DMA completion. We just start another DMA
+ * transfer unless overlay has been turned off
+ */
+static void camera_core_capture_callback(void *arg1, void *arg)
+{
+       struct camera_device *cam = (struct camera_device *)arg1;
+       int err;
+       unsigned long irqflags;
+       static int done = 0;
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       if (!cam->reading) {
+               done = 0;
+               cam->capture_started = 0;
+               spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+               return;
+       }
+
+       if (done < 14) {
+               ++done;
+               sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+               sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+               err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                                             camera_core_capture_callback,
+                                             NULL);
+       } else {
+               cam->capture_completed = 1;
+               if (cam->reading) {
+                       /* Wake up any process which are waiting for the
+                        * DMA to complete
+                        */
+                       wake_up_interruptible(&camera_dev->new_video_frame);
+                       sg_dma_address(&cam->capture_sglist) =
+                           cam->capture_base_phys;
+                       sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+                       err =
+                          camera_core_sgdma_queue(cam, &cam->capture_sglist,
+                                                  1,
+                                                  camera_core_capture_callback,
+                                                  NULL);
+               }
+       }
+
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+}
+
+static ssize_t camera_core_read(struct file *file, char *data, size_t count,
+                               loff_t *ppos)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+       int err;
+       unsigned long irqflags;
+       long timeout;
+#if 0                          /* Use video_buf to do capture */
+       int i;
+       for (i = 0; i < 14; i++)
+               videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       i = videobuf_read_one(file, &fh->vbq, data, count, ppos);
+       return i;
+#endif
+
+       if (!cam->capture_base) {
+               cam->capture_base = (unsigned long)
+                   dma_alloc_coherent(NULL,
+                                      cam->pix.sizeimage,
+                                      (dma_addr_t *) &
+                                      cam->capture_base_phys,
+                                      GFP_KERNEL | GFP_DMA);
+       }
+       if (!cam->capture_base) {
+               dev_err(cam->dev, "cannot allocate capture buffer\n");
+               return 0;
+       }
+
+       spin_lock_irqsave(&cam->capture_lock, irqflags);
+       cam->reading = fh;
+       cam->capture_started = 1;
+       sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys;
+       sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage;
+       spin_unlock_irqrestore(&cam->capture_lock, irqflags);
+
+       err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1,
+                                     camera_core_capture_callback, NULL);
+
+       /* Wait till DMA is completed */
+       timeout = HZ * 10;
+       cam->capture_completed = 0;
+       while (cam->capture_completed == 0) {
+               timeout = interruptible_sleep_on_timeout
+                   (&cam->new_video_frame, timeout);
+               if (timeout == 0) {
+                       dev_err(cam->dev, "timeout waiting video frame\n");
+                       return -EIO;    /* Time out */
+               }
+       }
+       /* Copy the data to the user buffer */
+       err = copy_to_user(data, (void *)cam->capture_base, cam->pix.sizeimage);
+       return (cam->pix.sizeimage - err);
+
+}
+
+static int camera_core_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct camera_fh *fh = file->private_data;
+
+       return videobuf_mmap_mapper(&fh->vbq, vma);
+}
+
+static int camera_core_release(struct inode *inode, struct file *file)
+{
+       struct camera_fh *fh = file->private_data;
+       struct camera_device *cam = fh->cam;
+
+       file->private_data = NULL;
+       kfree(fh);
+
+       spin_lock(&cam->img_lock);
+
+       if (cam->previewing == fh)
+               cam->previewing = NULL;
+       if (cam->streaming == fh)
+               cam->streaming = NULL;
+       if (cam->reading == fh)
+               cam->reading = NULL;
+
+       spin_unlock(&cam->img_lock);
+
+       camera_dev->cam_hardware->finish_dma(cam->hardware_data);
+
+       if (cam->capture_base) {
+               dma_free_coherent(NULL, cam->pix.sizeimage,
+                                 (void *)cam->capture_base,
+                                 cam->capture_base_phys);
+               cam->capture_base = 0;
+               cam->capture_base_phys = 0;
+       }
+       if (fh->vbq.read_buf) {
+               camera_core_vbq_release(&fh->vbq, fh->vbq.read_buf);
+               kfree(fh->vbq.read_buf);
+       }
+
+       module_put(cam->sdev->module);
+
+       cam->cam_hardware->close(cam->hardware_data);
+       cam->active = 0;
+       return 0;
+}
+
+static int camera_core_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct camera_device *cam = camera_dev;
+       struct camera_fh *fh;
+       struct v4l2_format format;
+       int rval;
+
+       if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+               return -ENODEV;
+
+       /* Allocate per-filehandle data */
+       fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+       file->private_data = fh;
+       fh->cam = cam;
+       fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       spin_lock(&cam->img_lock);
+       if (cam->active == 1) {
+               dev_err(cam->dev, "Camera device Active\n");
+               spin_unlock(&cam->img_lock);
+               rval = -EPERM;
+               goto err;
+       }
+       cam->active = 1;
+
+       if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+               spin_unlock(&cam->img_lock);
+               rval = -ENODEV;
+               goto err;
+       }
+
+       vidioc_int_g_fmt_cap(cam->sdev, &format);
+       spin_unlock(&cam->img_lock);
+
+       videobuf_queue_sg_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock,
+                           fh->type, V4L2_FIELD_NONE,
+                           sizeof(struct videobuf_buffer), fh);
+
+       cam->capture_completed = 0;
+       cam->capture_started = 0;
+
+       if (cam->cam_hardware->open(cam->hardware_data)) {
+               dev_err(cam->dev, "Camera IF configuration failed\n");
+               cam->active = 0;
+               rval = -ENODEV;
+               goto err;
+       }
+       rval = vidioc_s_fmt_cap(file, fh, &format);
+       if (rval) {
+               dev_err(cam->dev, "Camera sensor configuration failed (%d)\n",
+                       rval);
+               cam->cam_hardware->close(cam->hardware_data);
+               cam->active = 0;
+               rval = -ENODEV;
+               goto err;
+       }
+
+       return 0;
+
+err:
+       module_put(cam->sdev->module);
+       kfree(fh);
+       return rval;
+}
+
+#ifdef CONFIG_PM
+static int camera_core_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+
+       spin_lock(&cam->img_lock);
+       if (cam->active)
+               cam->cam_hardware->close(cam->hardware_data);
+
+       vidioc_int_s_power(cam->sdev, 0);
+       spin_unlock(&cam->img_lock);
+
+       return 0;
+}
+
+static int camera_core_resume(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+
+       spin_lock(&cam->img_lock);
+       vidioc_int_s_power(cam->sdev, 1);
+       if (cam->active) {
+               struct v4l2_format format;
+
+               cam->capture_completed = 1;
+               cam->cam_hardware->open(cam->hardware_data);
+
+               vidioc_int_g_fmt_cap(cam->sdev, &format);
+               vidioc_int_s_fmt_cap(cam->sdev, &format);
+               camera_sensor_if_enable(cam);
+
+               camera_core_sgdma_process(cam);
+       }
+       spin_unlock(&cam->img_lock);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct file_operations camera_core_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .read           = camera_core_read,
+       .poll           = camera_core_poll,
+       .ioctl          = video_ioctl2,
+       .mmap           = camera_core_mmap,
+       .open           = camera_core_open,
+       .release        = camera_core_release,
+};
+static ssize_t camera_streaming_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct camera_device *cam = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
+}
+
+static DEVICE_ATTR(streaming, S_IRUGO, camera_streaming_show, NULL);
+
+static void camera_device_unregister(struct v4l2_int_device *s)
+{
+       struct camera_device *cam = s->u.slave->master->priv;
+
+       camera_sensor_exit(cam);
+}
+
+static int camera_device_register(struct v4l2_int_device *s)
+{
+       struct camera_device *cam = s->u.slave->master->priv;
+       struct video_device *vfd;
+       int rval;
+
+       /* We already have a slave. */
+       if (cam->sdev)
+               return -EBUSY;
+
+       cam->sdev = s;
+
+       if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+               dev_err(cam->dev, "could not register sysfs entry\n");
+               rval = -EBUSY;
+               goto err;
+       }
+
+       /* Initialize the video_device struct */
+       vfd = cam->vfd = video_device_alloc();
+       if (!vfd) {
+               dev_err(cam->dev, " could not allocate video device struct\n");
+               rval = -ENOMEM;
+               goto err;
+       }
+
+       vfd->release = video_device_release;
+
+       strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+       vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+
+       /* Need to register for a VID_HARDWARE_* ID in videodev.h */
+       vfd->fops = &camera_core_fops;
+       video_set_drvdata(vfd, cam);
+       vfd->minor = -1;
+
+       vfd->vidioc_querycap = vidioc_querycap;
+       vfd->vidioc_enum_fmt_cap = vidioc_enum_fmt_cap;
+       vfd->vidioc_g_fmt_cap = vidioc_g_fmt_cap;
+       vfd->vidioc_s_fmt_cap = vidioc_s_fmt_cap;
+       vfd->vidioc_try_fmt_cap = vidioc_try_fmt_cap;
+       vfd->vidioc_reqbufs = vidioc_reqbufs;
+       vfd->vidioc_querybuf = vidioc_querybuf;
+       vfd->vidioc_qbuf = vidioc_qbuf;
+       vfd->vidioc_dqbuf = vidioc_dqbuf;
+       vfd->vidioc_streamon = vidioc_streamon;
+       vfd->vidioc_streamoff = vidioc_streamoff;
+       vfd->vidioc_enum_input = vidioc_enum_input;
+       vfd->vidioc_g_input = vidioc_g_input;
+       vfd->vidioc_s_input = vidioc_s_input;
+       vfd->vidioc_queryctrl = vidioc_queryctrl;
+       vfd->vidioc_g_ctrl = vidioc_g_ctrl;
+       vfd->vidioc_s_ctrl = vidioc_s_ctrl;
+       vfd->vidioc_g_fbuf = vidioc_g_fbuf;
+       vfd->vidioc_s_fbuf = vidioc_s_fbuf;
+       vfd->vidioc_overlay = vidioc_overlay;
+
+       dev_info(cam->dev, "%s interface with %s sensor\n",
+                cam->cam_hardware->name, cam->sdev->name);
+
+       if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+               dev_err(cam->dev,
+                       "could not register Video for Linux device\n");
+               rval = -ENODEV;
+               goto err;
+       }
+
+       rval = camera_sensor_init(cam);
+       if (rval)
+               goto err;
+
+       /* Disable the Camera after detection */
+       cam->cam_hardware->disable(cam->hardware_data);
+
+       return 0;
+
+err:
+       camera_device_unregister(s);
+
+       return rval;
+}
+
+static struct v4l2_int_master camera_master = {
+       .attach = camera_device_register,
+       .detach = camera_device_unregister,
+};
+
+static struct v4l2_int_device camera = {
+       .module = THIS_MODULE,
+       .name   = CAM_NAME,
+       .type   = v4l2_int_type_master,
+       .u      = {
+               .master = &camera_master
+       },
+};
+
+static int __init camera_core_probe(struct platform_device *pdev)
+{
+       struct camera_device *cam;
+       int status = 0;
+
+       cam = kzalloc(sizeof(struct camera_device), GFP_KERNEL);
+       if (!cam) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               status = -ENOMEM;
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, cam);
+
+       cam->dev = &pdev->dev;
+
+       /* Initialize the camera interface */
+       cam->cam_hardware = &camera_hardware_if;
+       cam->hardware_data = cam->cam_hardware->init();
+       if (!cam->hardware_data) {
+               dev_err(cam->dev, "cannot initialize interface hardware\n");
+               status = -ENODEV;
+               goto err;
+       }
+
+       /* Save the pointer to camera device in a global variable */
+       camera_dev = cam;
+
+       /* Initialize the videobuf queue ops */
+       cam->vbq_ops.buf_setup = camera_core_vbq_setup;
+       cam->vbq_ops.buf_prepare = camera_core_vbq_prepare;
+       cam->vbq_ops.buf_queue = camera_core_vbq_queue;
+       cam->vbq_ops.buf_release = camera_core_vbq_release;
+
+       /* Initialize the overlay interface */
+       cam->overlay_size = overlay_mem;
+       if (cam->overlay_size > 0) {
+               cam->overlay_base = (unsigned long)
+                   dma_alloc_coherent(NULL,
+                                      cam->overlay_size,
+                                      (dma_addr_t *) &
+                                      cam->overlay_base_phys,
+                                      GFP_KERNEL | GFP_DMA);
+               if (!cam->overlay_base) {
+                       dev_err(cam->dev,
+                               "cannot allocate overlay framebuffer\n");
+                       status = -ENOMEM;
+                       goto err;
+               }
+       }
+       memset((void *)cam->overlay_base, 0, cam->overlay_size);
+       spin_lock_init(&cam->overlay_lock);
+       spin_lock_init(&cam->capture_lock);
+
+       /* Initialize the spinlock used to serialize access to the image
+        * parameters
+        */
+       spin_lock_init(&cam->img_lock);
+
+       /* Initialize the wait queue */
+       init_waitqueue_head(&cam->new_video_frame);
+
+       /* Initialize the DMA structures */
+       camera_core_sgdma_init(cam);
+
+       platform_set_drvdata(pdev, cam);
+
+       camera.priv = cam;
+
+       if (v4l2_int_device_register(&camera))
+               goto err;
+
+       return 0;
+
+err:
+       vidioc_int_dev_exit(cam->sdev);
+       cam->overlay_base = 0;
+       return status;
+}
+
+static int camera_core_remove(struct platform_device *pdev)
+{
+       struct camera_device *cam = platform_get_drvdata(pdev);
+       struct video_device *vfd;
+
+       vfd = cam->vfd;
+       if (vfd) {
+               if (vfd->minor == -1) {
+                       /* The device never got registered, so release the
+                        * video_device struct directly
+                        */
+                       video_device_release(vfd);
+               } else {
+                       /* The unregister function will release the
+                        * video_device struct as well as unregistering it.
+                        */
+                       video_unregister_device(vfd);
+               }
+               cam->vfd = NULL;
+       }
+       if (cam->overlay_base) {
+               dma_free_coherent(NULL, cam->overlay_size,
+                                 (void *)cam->overlay_base,
+                                 cam->overlay_base_phys);
+               cam->overlay_base = 0;
+       }
+       cam->overlay_base_phys = 0;
+
+       vidioc_int_dev_exit(cam->sdev);
+       cam->cam_hardware->cleanup(cam->hardware_data);
+       kfree(cam);
+       camera_dev = NULL;
+
+       return 0;
+}
+
+static struct platform_driver camera_core_driver = {
+       .driver = {
+               .name   = CAM_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = camera_core_probe,
+       .remove         = camera_core_remove,
+#ifdef CONFIG_PM
+       .suspend        = camera_core_suspend,
+       .resume         = camera_core_resume,
+#endif
+};
+
+/* FIXME register omap16xx or omap24xx camera device in arch/arm/...
+ * system initialization code, with its resources and mux setup, NOT here.
+ * Then MODULE_ALIAS(CAM_NAME) so it hotplugs and coldplugs; this
+ * "legacy" driver style is trouble.
+ */
+static struct platform_device *cam;
+
+static void __exit camera_core_cleanup(void)
+{
+       platform_driver_unregister(&camera_core_driver);
+       platform_device_unregister(cam);
+}
+
+static char banner[] __initdata = KERN_INFO "OMAP Camera driver initializing\n";
+
+static int __init camera_core_init(void)
+{
+
+       printk(banner);
+       platform_driver_register(&camera_core_driver);
+
+       cam = platform_device_register_simple(CAM_NAME, -1, NULL, 0);
+
+       return 0;
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+                "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem,
+                "Maximum amount of memory for capture buffers "
+                "(default 4800KB)");
+
+module_init(camera_core_init);
+module_exit(camera_core_cleanup);
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..02ed5be
--- /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 <asm/scatterlist.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+struct camera_device;
+typedef void (*dma_callback_t)(void *arg1, void *arg2);
+
+struct sgdma_state {
+       const struct scatterlist *sglist;
+       int sglen;              /* number of sglist entries */
+       int next_sglist;        /* index of next sglist entry to process */
+       int queued_sglist;      /* number of sglist entries queued for DMA */
+       unsigned long csr;      /* DMA return code */
+       dma_callback_t callback;
+       void *arg;
+};
+
+/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued.
+ */
+#define NUM_SG_DMA VIDEO_MAX_FRAME+2
+
+/* per-device data structure */
+struct camera_device {
+       struct device *dev;
+       struct video_device *vfd;
+
+       spinlock_t overlay_lock;        /* spinlock for overlay DMA counter */
+       int overlay_cnt;                /* count of queued overlay DMA xfers */
+       struct scatterlist overlay_sglist;
+       unsigned long overlay_base_phys;
+       unsigned long overlay_base;
+       unsigned long overlay_size;
+
+       spinlock_t vbq_lock;            /* spinlock for videobuf queues */
+       struct videobuf_queue_ops vbq_ops;      /* videobuf queue operations */
+       unsigned long field_count;      /* field counter for videobuf_buffer */
+
+       /* scatter-gather DMA management */
+       spinlock_t sg_lock;
+       int free_sgdma; /* number of free sg dma slots */
+       int next_sgdma; /* index of next sg dma slot to use */
+       struct sgdma_state sgdma[NUM_SG_DMA];
+       char in_use;
+
+       /* The img_lock is used to serialize access to the image parameters for
+        * overlay and capture.  Need to use spin_lock_irq when writing to the
+        * reading, streaming, and previewing parameters.  A regular spin_lock
+        * will suffice for all other cases.
+        */
+       spinlock_t img_lock;
+
+       /* We allow reading from at most one filehandle at a time.
+        * non-NULL means reading is in progress.
+        */
+       struct camera_fh *reading;
+       /* We allow streaming from at most one filehandle at a time.
+        * non-NULL means streaming is in progress.
+        */
+       struct camera_fh *streaming;
+       /* We allow previewing from at most one filehandle at a time.
+        * non-NULL means previewing is in progress.
+        */
+       struct camera_fh *previewing;
+
+       /*
+        * Sensor interface parameters: interface type, CC_CTRL
+        * register value and interface specific data.
+        */
+       int if_type;
+       union {
+               struct parallel {
+                       u32 xclk;
+               } bt656;
+       } if_u;
+       /* Pointer to the sensor interface ops */
+       struct v4l2_int_device *sdev;
+
+       /* Pointer to the camera interface hardware ops */
+       struct camera_hardware *cam_hardware;
+       void *hardware_data;
+
+       /* pix defines the size and pixel format of the image captured by the
+        * sensor.  This also defines the size of the framebuffers.  The
+        * same pool of framebuffers is used for video capture and video
+        * overlay.  These parameters are set/queried by the
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type.
+        */
+       struct v4l2_pix_format pix;
+
+       /* crop defines the size and offset of the video overlay source window
+        * within the framebuffer.  These parameters are set/queried by the
+        * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type.
+        * The cropping rectangle allows a subset of the captured image to be
+        * previewed.  It only affects the portion of the image previewed, not
+        * captured; the entire camera image is always captured.
+        */
+       struct v4l2_rect crop;
+
+       /* win defines the size and offset of the video overlay target window
+        * within the video display.  These parameters are set/queried by the
+        * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type.
+        */
+       struct v4l2_window win;
+
+       /* fbuf reflects the size of the video display.  It is queried with the
+        * VIDIOC_G_FBUF ioctl.  The size of the video display cannot be
+        * changed with the VIDIOC_S_FBUF ioctl.
+        */
+       struct v4l2_framebuffer fbuf;
+
+       /* end of generic stuff, the above should be common to all omaps */
+
+       /* note, 2420 uses videobuf to do caprure, it is more memory efficient
+          we need 1710 and 2420 do capture in the same way */
+       /* Variables to store the capture state */
+       /* Wait till DMA is completed */
+       wait_queue_head_t new_video_frame;
+       char capture_completed;
+       char capture_started;
+       spinlock_t capture_lock;
+       struct scatterlist capture_sglist;
+       unsigned long capture_base;
+       unsigned long capture_base_phys;
+
+       char active;
+};
+
+/* per-filehandle data structure */
+struct camera_fh {
+       struct camera_device *cam;
+       enum v4l2_buf_type type;
+       struct videobuf_queue vbq;
+};
+
+#define CAM_NAME "omap_camera"
+
+#endif /* CAMERA_CORE__H */
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/omap16xxcam.c b/drivers/media/video/omap/omap16xxcam.c
new file mode 100644 (file)
index 0000000..0b5a302
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * 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 <mach/irqs.h>
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <asm/mach-types.h>
+
+#include "omap16xxcam.h"
+#include "camera_hw_if.h"
+#include "camera_core.h"
+
+#define CONF_CAMERAIF_RESET_R 5
+#define EN_PER   0
+
+/* NUM_CAMDMA_CHANNELS is the number of logical channels used for
+ * DMA data transfer.
+ */
+#define NUM_CAMDMA_CHANNELS 2
+
+typedef struct {
+       unsigned int ctrlclock;         /* 00 */
+       unsigned int it_status;         /* 04 */
+       unsigned int mode;              /* 08 */
+       unsigned int status;            /* 0C */
+       unsigned int camdata;           /* 10 */
+       unsigned int gpio;              /* 14 */
+       unsigned int peak_counter;      /* 18 */
+} camera_regs_t;
+
+struct camdma_state {
+       dma_callback_t callback;
+       void *arg1;
+       void *arg2;
+};
+
+struct omap16xxcam {
+       camera_regs_t *camera_regs;
+       unsigned long iobase_phys;
+
+       /* Frequency (in Hz) of camera interface functional clock (ocp_clk) */
+       unsigned long ocp_clk;
+
+       struct clk *func_clk;
+
+       /* DMA related stuff */
+       spinlock_t dma_lock;
+       int free_dmach;
+       int next_dmach;
+       struct camdma_state camdma[NUM_CAMDMA_CHANNELS];
+       int dma_channel_number1;
+       int dma_channel_number2;
+
+       wait_queue_head_t vsync_wait;
+
+       int new;
+};
+static struct omap16xxcam hardware_data;
+
+static int omap16xxcam_set_xclk(int, void *);
+static void omap16xx_cam_dma_link_callback(int, unsigned short, void *);
+
+/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration
+ * register.
+ */
+static void omap16xx_cam_clear_fifo(struct omap16xxcam *data)
+{
+       data->camera_regs->mode |= RAZ_FIFO;
+       udelay(10);
+       data->camera_regs->mode &= ~RAZ_FIFO;
+}
+
+static void omap16xx_cam_reset(struct omap16xxcam *data, int yes)
+{
+       if (machine_is_omap_h3())
+               data->camera_regs->gpio = yes ? 0 : 1;
+       else
+               data->camera_regs->gpio = yes ? 1 : 0;
+}
+
+static void omap16xx_cam_init(void)
+{
+       /*
+        * FIXME - Use mux API's instead of directly writing in to MUX registers
+        */
+       omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21),
+                   FUNC_MUX_CTRL_4);
+       omap_writel(0, FUNC_MUX_CTRL_5);
+       omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17),
+                   PULL_DWN_CTRL_0);
+       omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0);
+
+       omap_writel(0xeaef, COMP_MODE_CTRL_0);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) &
+                   ~(1 << CONF_CAMERAIF_RESET_R), OMAP1610_RESET_CONTROL);
+       omap_writel(omap_readl(OMAP1610_RESET_CONTROL) |
+                   (1 << CONF_CAMERAIF_RESET_R), OMAP1610_RESET_CONTROL);
+
+       /* Enable peripheral reset */
+       omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2);
+
+       /* Enable peripheral clock */
+       clk_enable(hardware_data.func_clk);
+}
+
+static void omap16xx_cam_waitfor_syncedge(struct omap16xxcam *data,
+                                         u32 edge_mask)
+{
+       data->camera_regs->mode =
+           (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask;
+       do {
+               interruptible_sleep_on(&data->vsync_wait);
+       } while (signal_pending(current));
+}
+
+static void omap16xx_cam_configure_dma(struct omap16xxcam *data)
+{
+
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT)
+           | EN_DMA | EN_FIFO_FULL;
+       data->camera_regs->ctrlclock |= LCLK_EN;
+}
+
+/* Acquire h/w resources DMA */
+static int omap16xx_cam_link_open(struct omap16xxcam *data)
+{
+       int ret;
+
+       /* Acquire first DMA channel */
+       ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX,
+                              "camera dma 1",
+                              omap16xx_cam_dma_link_callback,
+                              (void *)data, &data->dma_channel_number1);
+       if (ret)
+               return ret;
+
+       /* Acquire second DMA channel */
+       ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX,
+                              "camera dma 2",
+                              omap16xx_cam_dma_link_callback,
+                              (void *)data, &data->dma_channel_number2);
+       if (ret) {
+               printk(KERN_ERR "No DMA available for camera\n");
+               return ret;
+       }
+       data->next_dmach = data->dma_channel_number1;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number1) =
+           data->dma_channel_number2;
+       OMAP_DMA_CLNK_CTRL_REG(data->dma_channel_number2) =
+           data->dma_channel_number1;
+
+       return 0;
+}
+
+/* Free h/w resources, stop i/f */
+static int omap16xx_cam_link_close(struct omap16xxcam *data)
+{
+       /* Free DMA channels */
+       omap_stop_dma(data->dma_channel_number1);
+       omap_stop_dma(data->dma_channel_number2);
+
+       omap_free_dma(data->dma_channel_number1);
+       omap_free_dma(data->dma_channel_number2);
+
+       return 0;
+}
+
+/* DMA callback routine. */
+static void omap16xx_cam_dma_link_callback(int lch, unsigned short ch_status,
+                                          void *data)
+{
+       int count;
+       void *arg1, *arg2;
+       struct sgdma_state *sgdma = sgdma;
+       struct omap16xxcam *cam = (struct omap16xxcam *)data;
+       dma_callback_t callback;
+
+       spin_lock(&cam->dma_lock);
+       if (cam->free_dmach == 2) {
+               printk(KERN_ERR "callback all CHANNELS WERE IDLE \n");
+               spin_unlock(&cam->dma_lock);
+               return;
+       }
+       if (cam->free_dmach == 0) {
+               lch = cam->next_dmach;
+       } else {
+               lch = cam->next_dmach == cam->dma_channel_number1 ?
+                   cam->dma_channel_number2 : cam->dma_channel_number1;
+       }
+
+       while (cam->free_dmach < 2) {
+               if (OMAP_DMA_CCR_REG(lch) & (1 << 7))
+                       break;
+
+               count = (lch == cam->dma_channel_number2) ? 1 : 0;
+
+               callback = cam->camdma[count].callback;
+               arg1 = cam->camdma[count].arg1;
+               arg2 = cam->camdma[count].arg2;
+               cam->free_dmach++;
+
+               spin_unlock(&cam->dma_lock);
+               callback(arg1, arg2);
+               spin_lock(&cam->dma_lock);
+
+               lch =
+                   (lch ==
+                    cam->dma_channel_number2) ? cam->
+                   dma_channel_number1 : cam->dma_channel_number2;
+       }
+       spin_unlock(&cam->dma_lock);
+
+}
+
+static irqreturn_t omap16xx_cam_isr(int irq, void *client_data)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)client_data;
+       unsigned int itstat = data->camera_regs->it_status;
+
+       /* VSYNC UP interrupt, start filling FIFO and enabling DMA */
+       if (itstat & V_UP) {
+               data->camera_regs->mode &= ~EN_V_UP;
+               omap16xx_cam_clear_fifo(data);
+               omap16xx_cam_configure_dma(data);
+               omap_start_dma(data->next_dmach);
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & V_DOWN) {
+               data->camera_regs->mode &= ~EN_V_DOWN;
+               wake_up_interruptible(&data->vsync_wait);
+       }
+
+       if (itstat & H_UP)
+               printk(KERN_INFO "H_UP\n");
+
+       if (itstat & H_DOWN)
+               printk(KERN_INFO "H_DOWN\n");
+
+       if (itstat & FIFO_FULL) {
+               omap16xx_cam_clear_fifo(data);
+               printk(KERN_INFO "FIFO_FULL\n");
+       }
+
+       if (itstat & DATA_XFER)
+               printk(KERN_INFO "DATA_TRANS\n");
+
+       return IRQ_HANDLED;
+}
+
+/* ------------- Below are interface functions -----------------
+ * ------------- These functions are named omap16xxcam_<name> --
+ */
+static int omap16xxcam_init_dma(void *priv)
+{
+       int ch;
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       data->free_dmach = 2;
+       for (ch = 0; ch < 2; ++ch) {
+               data->camdma[ch].callback = NULL;
+               data->camdma[ch].arg1 = NULL;
+               data->camdma[ch].arg2 = NULL;
+       }
+
+       return 0;
+}
+
+/* Start the DMA of chains */
+static int omap16xxcam_start_dma(struct sgdma_state *sgdma,
+                                dma_callback_t callback, void *arg1,
+                                void *arg2, void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+       struct scatterlist *sglist;
+       unsigned long irqflags;
+       int dmach;
+       int prev_dmach;
+       int count;
+
+       spin_lock_irqsave(&data->dma_lock, irqflags);
+       sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist);
+
+       if (!data->free_dmach) {
+               spin_unlock_irqrestore(&data->dma_lock, irqflags);
+               return -EBUSY;
+       }
+       dmach = data->next_dmach;
+       count = (dmach == data->dma_channel_number2) ? 1 : 0;
+       data->camdma[count].callback = callback;
+       data->camdma[count].arg1 = arg1;
+       data->camdma[count].arg2 = arg2;
+
+       if (cpu_is_omap1710())
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1,
+                                       OMAP_DMA_AMODE_CONSTANT,
+                                       CAM_CAMDATA_REG, 0, 0);
+       else
+               omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB,
+                                       OMAP_DMA_AMODE_CONSTANT,
+                                       CAM_CAMDATA_REG, 0, 0);
+
+       omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF,
+                                OMAP_DMA_AMODE_POST_INC,
+                                sg_dma_address(sglist), 0, 0);
+
+       omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32,
+                                    FIFO_TRIGGER_LVL,
+                                    sg_dma_len(sglist) / (4 *
+                                                          FIFO_TRIGGER_LVL),
+                                    OMAP_DMA_SYNC_FRAME, 0, 0);
+
+       OMAP_DMA_CLNK_CTRL_REG(dmach) &= ~(1 << 15);
+
+       prev_dmach = (dmach == data->dma_channel_number2) ?
+           data->dma_channel_number1 : data->dma_channel_number2;
+
+       if (data->new) {
+               data->new = 0;
+               omap16xx_cam_waitfor_syncedge(data, EN_V_UP);
+       } else {
+               if (OMAP_DMA_CCR_REG(prev_dmach) & (1 << 7))
+                       OMAP_DMA_CLNK_CTRL_REG(prev_dmach) |= (1 << 15);
+               else {
+                       /* No transfer is in progress */
+                       omap_start_dma(dmach);
+               }
+       }
+
+       data->next_dmach = prev_dmach;
+       data->free_dmach--;
+       spin_unlock_irqrestore(&data->dma_lock, irqflags);
+       return 0;
+}
+
+int static omap16xxcam_finish_dma(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       while (data->free_dmach < 2)
+               mdelay(1);
+
+       return 0;
+}
+
+/* Enables the camera. Takes camera out of reset. Enables the clocks. */
+static int omap16xxcam_enable(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       omap16xx_cam_reset(data, 1);
+
+       /* Give clock to camera_module */
+       data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT);
+       data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN;
+
+       omap16xx_cam_clear_fifo(data);
+
+       /* Wait for camera to settle down */
+       mdelay(5);
+
+       return 0;
+}
+
+/* Disables all the camera clocks. Put the camera interface in reset. */
+static int omap16xxcam_disable(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       omap16xx_cam_clear_fifo(data);
+
+       data->camera_regs->ctrlclock = 0x00000000;
+       data->camera_regs->mode = 0x00000000;
+
+       omap16xx_cam_reset(data, 0);
+
+       return 0;
+}
+
+/* Abort the data transfer */
+static int omap16xxcam_abort(void *priv)
+{
+       return omap16xxcam_disable(priv);
+}
+
+static int omap16xxcam_set_xclk(int xclk, void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+       int xclk_val;
+       int divisor = 1;
+       divisor = data->ocp_clk / xclk;
+       if (divisor * xclk < data->ocp_clk)
+               ++divisor;
+
+       switch (divisor) {
+       case 1:
+       case 2:
+               xclk_val = FOSCMOD_TC2_CK2;
+               break;
+       case 3:
+               xclk_val = FOSCMOD_TC2_CK3;
+               break;
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+               xclk_val = FOSCMOD_TC2_CK4;
+               break;
+       case 8:
+       case 9:
+               xclk_val = FOSCMOD_TC2_CK8;
+               break;
+       case 10:
+       case 11:
+               xclk_val = FOSCMOD_TC2_CK10;
+               break;
+       case 12:
+       case 13:
+       case 14:
+       case 15:
+               xclk_val = FOSCMOD_TC2_CK12;
+               break;
+       case 16:
+               xclk_val = FOSCMOD_TC2_CK16;
+               break;
+       default:
+               xclk_val = FOSCMOD_TC2_CK16;
+       }
+
+       /* Follow the protocol to change the XCLK clock */
+       data->camera_regs->ctrlclock &= ~CAMEXCLK_EN;
+       data->camera_regs->ctrlclock |= xclk_val;
+       data->camera_regs->ctrlclock |= CAMEXCLK_EN;
+
+       return (data->ocp_clk / divisor);
+}
+
+static int omap16xxcam_open(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+       int ret;
+
+       ret = request_irq(INT_CAMERA, omap16xx_cam_isr, IRQF_DISABLED,
+                         "camera", data);
+       if (ret) {
+               printk(KERN_ERR "FAILED to acquire IRQ\n");
+               return ret;
+       }
+
+       data->new = 1;
+       omap16xxcam_enable(data);
+       omap16xxcam_init_dma(data);
+
+       return omap16xx_cam_link_open(data);
+}
+
+static int omap16xxcam_close(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       omap16xxcam_disable(priv);
+
+       free_irq(INT_CAMERA, data);
+
+       return omap16xx_cam_link_close(data);
+}
+
+static int omap16xxcam_cleanup(void *priv)
+{
+       struct omap16xxcam *data = (struct omap16xxcam *)priv;
+
+       if (!data->camera_regs)
+               return -EINVAL;
+
+       omap16xxcam_disable(data);
+       if (cpu_is_omap1710())
+               iounmap((void *)data->camera_regs);
+       data->camera_regs = NULL;
+
+       if (data->iobase_phys) {
+               release_mem_region(data->iobase_phys, CAMERA_IOSIZE);
+               data->iobase_phys = 0;
+       }
+
+       if (hardware_data.func_clk) {
+               clk_disable(hardware_data.func_clk);
+               clk_put(hardware_data.func_clk);
+               hardware_data.func_clk = NULL;
+       }
+
+       return 0;
+}
+
+/* Initialize the OMAP camera interface */
+static void *omap16xxcam_init(void)
+{
+       unsigned long cam_iobase;
+
+       if (!request_mem_region(CAMERA_BASE, CAMERA_IOSIZE,
+                               camera_hardware_if.name)) {
+               pr_debug("%s is already in use\n", camera_hardware_if.name);
+               return NULL;
+       }
+
+       if (cpu_is_omap1710()) {
+               cam_iobase = (unsigned long)ioremap(CAMERA_BASE, CAMERA_IOSIZE);
+               if (!cam_iobase) {
+                       printk(KERN_ERR "CANNOT MAP CAMERA REGISTER\n");
+                       return NULL;
+               }
+       } else
+               cam_iobase = OMAP1_IO_ADDRESS(CAMERA_BASE);
+
+       /* Set the base address of the camera registers */
+       hardware_data.camera_regs = (camera_regs_t *) cam_iobase;
+       hardware_data.iobase_phys = (unsigned long)CAMERA_BASE;
+
+       /* Get the input clock value to camera interface and store it */
+       if (cpu_is_omap1710())
+               hardware_data.func_clk = clk_get(0, "tc2_ck");
+       else
+               hardware_data.func_clk = clk_get(0, "armper_ck");
+       hardware_data.ocp_clk = clk_get_rate(hardware_data.func_clk);
+
+       /* Initialize the camera IF */
+       omap16xx_cam_init();
+       /* Enable it. This is needed for sensor detection */
+       omap16xxcam_enable((void *)&hardware_data);
+       /* Initialize DMA data */
+       spin_lock_init(&hardware_data.dma_lock);
+
+       init_waitqueue_head(&hardware_data.vsync_wait);
+       return (void *)&hardware_data;
+}
+
+struct camera_hardware camera_hardware_if = {
+       .version        = 0x01,
+       .name           = "OMAP16xx Parallel Camera",
+       .init           = omap16xxcam_init,
+       .cleanup        = omap16xxcam_cleanup,
+       .open           = omap16xxcam_open,
+       .close          = omap16xxcam_close,
+       .enable         = omap16xxcam_enable,
+       .disable        = omap16xxcam_disable,
+       .abort          = omap16xxcam_abort,
+       .set_xclk       = omap16xxcam_set_xclk,
+       .init_dma       = omap16xxcam_init_dma,
+       .start_dma      = omap16xxcam_start_dma,
+       .finish_dma     = omap16xxcam_finish_dma,
+};
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/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c
new file mode 100644 (file)
index 0000000..5de0b6b
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * drivers/media/video/omap24xxcam-dma.c
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com> and
+ *                    David Cohen <david.cohen@indt.org.br>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+
+#include "omap24xxcam.h"
+
+/*
+ *
+ * DMA hardware.
+ *
+ */
+
+/* Ack all interrupt on CSR and IRQSTATUS_L0 */
+static void omap24xxcam_dmahw_ack_all(unsigned long base)
+{
+       u32 csr;
+       int i;
+
+       for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
+               csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
+               /* ack interrupt in CSR */
+               omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
+       }
+       omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
+}
+
+/* Ack dmach on CSR and IRQSTATUS_L0 */
+static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
+{
+       u32 csr;
+
+       csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
+       /* ack interrupt in CSR */
+       omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
+       /* ack interrupt in IRQSTATUS */
+       omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
+
+       return csr;
+}
+
+static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
+{
+       return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
+}
+
+static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
+                                            dma_addr_t start, u32 len)
+{
+       omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+                           CAMDMA_CCR_SEL_SRC_DST_SYNC
+                           | CAMDMA_CCR_BS
+                           | CAMDMA_CCR_DST_AMODE_POST_INC
+                           | CAMDMA_CCR_SRC_AMODE_POST_INC
+                           | CAMDMA_CCR_FS
+                           | CAMDMA_CCR_WR_ACTIVE
+                           | CAMDMA_CCR_RD_ACTIVE
+                           | CAMDMA_CCR_SYNCHRO_CAMERA);
+       omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
+       omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
+       omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
+       omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
+                           CAMDMA_CSDP_WRITE_MODE_POSTED
+                           | CAMDMA_CSDP_DST_BURST_EN_32
+                           | CAMDMA_CSDP_DST_PACKED
+                           | CAMDMA_CSDP_SRC_BURST_EN_32
+                           | CAMDMA_CSDP_SRC_PACKED
+                           | CAMDMA_CSDP_DATA_TYPE_8BITS);
+       omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
+       omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
+       omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
+       omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
+       omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
+       omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
+       omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
+                           CAMDMA_CSR_MISALIGNED_ERR
+                           | CAMDMA_CSR_SECURE_ERR
+                           | CAMDMA_CSR_TRANS_ERR
+                           | CAMDMA_CSR_BLOCK
+                           | CAMDMA_CSR_DROP);
+       omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
+                           CAMDMA_CICR_MISALIGNED_ERR_IE
+                           | CAMDMA_CICR_SECURE_ERR_IE
+                           | CAMDMA_CICR_TRANS_ERR_IE
+                           | CAMDMA_CICR_BLOCK_IE
+                           | CAMDMA_CICR_DROP_IE);
+}
+
+static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
+{
+       omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
+                           CAMDMA_CCR_SEL_SRC_DST_SYNC
+                           | CAMDMA_CCR_BS
+                           | CAMDMA_CCR_DST_AMODE_POST_INC
+                           | CAMDMA_CCR_SRC_AMODE_POST_INC
+                           | CAMDMA_CCR_ENABLE
+                           | CAMDMA_CCR_FS
+                           | CAMDMA_CCR_SYNCHRO_CAMERA);
+}
+
+static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
+                                            int free_dmach)
+{
+       int prev_dmach, ch;
+
+       if (dmach == 0)
+               prev_dmach = NUM_CAMDMA_CHANNELS - 1;
+       else
+               prev_dmach = dmach - 1;
+       omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
+                           CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
+       /* Did we chain the DMA transfer before the previous one
+        * finished?
+        */
+       ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
+       while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
+                & CAMDMA_CCR_ENABLE)) {
+               if (ch == dmach) {
+                       /* The previous transfer has ended and this one
+                        * hasn't started, so we must not have chained
+                        * to the previous one in time.  We'll have to
+                        * start it now.
+                        */
+                       omap24xxcam_dmahw_transfer_start(base, dmach);
+                       break;
+               } else
+                       ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
+       }
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
+{
+       /* mask all interrupts from this channel */
+       omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
+       /* unlink this channel */
+       omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
+                             CAMDMA_CLNK_CTRL_ENABLE_LNK);
+       /* disable this channel */
+       omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
+}
+
+static void omap24xxcam_dmahw_init(unsigned long base)
+{
+       omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
+                           CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
+                           | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
+                           | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
+
+       omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
+                             CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
+
+       omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
+}
+
+/*
+ *
+ * Individual DMA channel handling.
+ *
+ */
+
+/* Start a DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully started, or non-zero if all
+ * DMA channels are already in use or starting is currently inhibited.
+ */
+static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
+                                u32 len, dma_callback_t callback, void *arg)
+{
+       unsigned long flags;
+       int dmach;
+
+       spin_lock_irqsave(&dma->lock, flags);
+
+       if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
+               spin_unlock_irqrestore(&dma->lock, flags);
+               return -EBUSY;
+       }
+
+       dmach = dma->next_dmach;
+
+       dma->ch_state[dmach].callback = callback;
+       dma->ch_state[dmach].arg = arg;
+
+       omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
+
+       /* We're ready to start the DMA transfer. */
+
+       if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+               /* A transfer is already in progress, so try to chain to it. */
+               omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
+                                                dma->free_dmach);
+       } else {
+               /* No transfer is in progress, so we'll just start this one
+                * now.
+                */
+               omap24xxcam_dmahw_transfer_start(dma->base, dmach);
+       }
+
+       dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
+       dma->free_dmach--;
+
+       spin_unlock_irqrestore(&dma->lock, flags);
+
+       return 0;
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. The DMA
+ * controller may not be idle after this routine completes, because
+ * the completion routines might start new transfers.
+ */
+static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
+{
+       unsigned long flags;
+       int dmach, i, free_dmach;
+       dma_callback_t callback;
+       void *arg;
+
+       spin_lock_irqsave(&dma->lock, flags);
+
+       /* stop any DMA transfers in progress */
+       dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
+       for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
+               omap24xxcam_dmahw_abort_ch(dma->base, dmach);
+               dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
+       }
+
+       /* We have to be careful here because the callback routine
+        * might start a new DMA transfer, and we only want to abort
+        * transfers that were started before this routine was called.
+        */
+       free_dmach = dma->free_dmach;
+       while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
+              (free_dmach < NUM_CAMDMA_CHANNELS)) {
+               dmach = (dma->next_dmach + dma->free_dmach)
+                       % NUM_CAMDMA_CHANNELS;
+               callback = dma->ch_state[dmach].callback;
+               arg = dma->ch_state[dmach].arg;
+               dma->free_dmach++;
+               free_dmach++;
+               if (callback) {
+                       /* leave interrupts disabled during callback */
+                       spin_unlock(&dma->lock);
+                       (*callback) (dma, csr, arg);
+                       spin_lock(&dma->lock);
+               }
+       }
+
+       spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+/* Abort all chained DMA transfers. After all transfers have been
+ * aborted and the DMA controller is idle, the completion routines for
+ * any aborted transfers will be called in sequence. If the completion
+ * routines attempt to start a new DMA transfer it will fail, so the
+ * DMA controller will be idle after this routine completes.
+ */
+static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
+{
+       atomic_inc(&dma->dma_stop);
+       omap24xxcam_dma_abort(dma, csr);
+       atomic_dec(&dma->dma_stop);
+}
+
+/* Camera DMA interrupt service routine. */
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
+{
+       int dmach;
+       dma_callback_t callback;
+       void *arg;
+       u32 csr;
+       const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+               | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+               | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+       spin_lock(&dma->lock);
+
+       if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
+               /* A camera DMA interrupt occurred while all channels
+                * are idle, so we'll acknowledge the interrupt in the
+                * IRQSTATUS register and exit.
+                */
+               omap24xxcam_dmahw_ack_all(dma->base);
+               spin_unlock(&dma->lock);
+               return;
+       }
+
+       while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
+               dmach = (dma->next_dmach + dma->free_dmach)
+                       % NUM_CAMDMA_CHANNELS;
+               if (omap24xxcam_dmahw_running(dma->base, dmach)) {
+                       /* This buffer hasn't finished yet, so we're done. */
+                       break;
+               }
+               csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
+               if (csr & csr_error) {
+                       /* A DMA error occurred, so stop all DMA
+                        * transfers in progress.
+                        */
+                       spin_unlock(&dma->lock);
+                       omap24xxcam_dma_stop(dma, csr);
+                       return;
+               } else {
+                       callback = dma->ch_state[dmach].callback;
+                       arg = dma->ch_state[dmach].arg;
+                       dma->free_dmach++;
+                       if (callback) {
+                               spin_unlock(&dma->lock);
+                               (*callback) (dma, csr, arg);
+                               spin_lock(&dma->lock);
+                       }
+               }
+       }
+
+       spin_unlock(&dma->lock);
+
+       omap24xxcam_sgdma_process(
+               container_of(dma, struct omap24xxcam_sgdma, dma));
+}
+
+void omap24xxcam_dma_hwinit(const struct omap24xxcam_dma *dma)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dma->lock, flags);
+
+       omap24xxcam_dmahw_init(dma->base);
+
+       spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
+                                unsigned long base)
+{
+       int ch;
+
+       /* group all channels on DMA IRQ0 and unmask irq */
+       spin_lock_init(&dma->lock);
+       dma->base = base;
+       dma->free_dmach = NUM_CAMDMA_CHANNELS;
+       dma->next_dmach = 0;
+       for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
+               dma->ch_state[ch].callback = NULL;
+               dma->ch_state[ch].arg = NULL;
+       }
+}
+
+/*
+ *
+ * Scatter-gather DMA.
+ *
+ * High-level DMA construct for transferring whole picture frames to
+ * memory that is discontinuous.
+ *
+ */
+
+/* DMA completion routine for the scatter-gather DMA fragments. */
+static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
+                                      void *arg)
+{
+       struct omap24xxcam_sgdma *sgdma =
+               container_of(dma, struct omap24xxcam_sgdma, dma);
+       int sgslot = (int)arg;
+       struct sgdma_state *sg_state;
+       const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+               | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+               | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+       spin_lock(&sgdma->lock);
+
+       /* We got an interrupt, we can remove the timer */
+       del_timer(&sgdma->reset_timer);
+
+       sg_state = sgdma->sg_state + sgslot;
+       if (!sg_state->queued_sglist) {
+               spin_unlock(&sgdma->lock);
+               printk(KERN_ERR "%s: sgdma completed when none queued!\n",
+                      __FUNCTION__);
+               return;
+       }
+
+       sg_state->csr |= csr;
+       if (!--sg_state->queued_sglist) {
+               /* Queue for this sglist is empty, so check to see if we're
+                * done.
+                */
+               if ((sg_state->next_sglist == sg_state->sglen)
+                   || (sg_state->csr & csr_error)) {
+                       sgdma_callback_t callback = sg_state->callback;
+                       void *arg = sg_state->arg;
+                       u32 sg_csr = sg_state->csr;
+                       /* All done with this sglist */
+                       sgdma->free_sgdma++;
+                       if (callback) {
+                               spin_unlock(&sgdma->lock);
+                               (*callback) (sgdma, sg_csr, arg);
+                               return;
+                       }
+               }
+       }
+
+       spin_unlock(&sgdma->lock);
+}
+
+/* Start queued scatter-gather DMA transfers. */
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
+{
+       unsigned long flags;
+       int queued_sgdma, sgslot;
+       struct sgdma_state *sg_state;
+       const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+               | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+               | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+
+       spin_lock_irqsave(&sgdma->lock, flags);
+
+       queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
+       sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+       while (queued_sgdma > 0) {
+               sg_state = sgdma->sg_state + sgslot;
+               while ((sg_state->next_sglist < sg_state->sglen) &&
+                      !(sg_state->csr & csr_error)) {
+                       const struct scatterlist *sglist;
+                       unsigned int len;
+
+                       sglist = sg_state->sglist + sg_state->next_sglist;
+                       /* try to start the next DMA transfer */
+                       if (sg_state->next_sglist + 1 == sg_state->sglen) {
+                               /*
+                                *  On the last sg, we handle the case where
+                                *  cam->img.pix.sizeimage % PAGE_ALIGN != 0
+                                */
+                               len = sg_state->len - sg_state->bytes_read;
+                       } else {
+                               len = sg_dma_len(sglist);
+                       }
+
+                       if (omap24xxcam_dma_start(&sgdma->dma,
+                                                 sg_dma_address(sglist),
+                                                 len,
+                                                 omap24xxcam_sgdma_callback,
+                                                 (void *)sgslot)) {
+                               /* DMA start failed */
+                               spin_unlock_irqrestore(&sgdma->lock, flags);
+                               return;
+                       } else {
+                               unsigned long expires;
+                               /* DMA start was successful */
+                               sg_state->next_sglist++;
+                               sg_state->bytes_read += len;
+                               sg_state->queued_sglist++;
+
+                               /* We start the reset timer */
+                               expires = jiffies + HZ;
+                               mod_timer(&sgdma->reset_timer, expires);
+                       }
+               }
+               queued_sgdma--;
+               sgslot = (sgslot + 1) % NUM_SG_DMA;
+       }
+
+       spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+/*
+ * Queue a scatter-gather DMA transfer from the camera to memory.
+ * Returns zero if the transfer was successfully queued, or non-zero
+ * if all of the scatter-gather slots are already in use.
+ */
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+                           const struct scatterlist *sglist, int sglen,
+                           int len, sgdma_callback_t callback, void *arg)
+{
+       unsigned long flags;
+       struct sgdma_state *sg_state;
+
+       if ((sglen < 0) || ((sglen > 0) & !sglist))
+               return -EINVAL;
+
+       spin_lock_irqsave(&sgdma->lock, flags);
+
+       if (!sgdma->free_sgdma) {
+               spin_unlock_irqrestore(&sgdma->lock, flags);
+               return -EBUSY;
+       }
+
+       sg_state = sgdma->sg_state + sgdma->next_sgdma;
+
+       sg_state->sglist = sglist;
+       sg_state->sglen = sglen;
+       sg_state->next_sglist = 0;
+       sg_state->bytes_read = 0;
+       sg_state->len = len;
+       sg_state->queued_sglist = 0;
+       sg_state->csr = 0;
+       sg_state->callback = callback;
+       sg_state->arg = arg;
+
+       sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
+       sgdma->free_sgdma--;
+
+       spin_unlock_irqrestore(&sgdma->lock, flags);
+
+       omap24xxcam_sgdma_process(sgdma);
+
+       return 0;
+}
+
+/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
+ * Any queued scatter-gather DMA transactions that have not yet been started
+ * will remain queued.  The DMA controller will be idle after this routine
+ * completes.  When the scatter-gather queue is restarted, the next
+ * scatter-gather DMA transfer will begin at the start of a new transaction.
+ */
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
+{
+       unsigned long flags;
+       int sgslot;
+       struct sgdma_state *sg_state;
+       u32 csr = CAMDMA_CSR_TRANS_ERR;
+
+       /* stop any DMA transfers in progress */
+       omap24xxcam_dma_stop(&sgdma->dma, csr);
+
+       spin_lock_irqsave(&sgdma->lock, flags);
+
+       if (sgdma->free_sgdma < NUM_SG_DMA) {
+               sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
+               sg_state = sgdma->sg_state + sgslot;
+               if (sg_state->next_sglist != 0) {
+                       /* This DMA transfer was in progress, so abort it. */
+                       sgdma_callback_t callback = sg_state->callback;
+                       void *arg = sg_state->arg;
+                       sgdma->free_sgdma++;
+                       if (callback) {
+                               /* leave interrupts masked */
+                               spin_unlock(&sgdma->lock);
+                               (*callback) (sgdma, csr, arg);
+                               spin_lock(&sgdma->lock);
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&sgdma->lock, flags);
+}
+
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+                           unsigned long base,
+                           void (*reset_callback)(unsigned long data),
+                           unsigned long reset_callback_data)
+{
+       int sg;
+
+       spin_lock_init(&sgdma->lock);
+       sgdma->free_sgdma = NUM_SG_DMA;
+       sgdma->next_sgdma = 0;
+       for (sg = 0; sg < NUM_SG_DMA; sg++) {
+               sgdma->sg_state[sg].sglen = 0;
+               sgdma->sg_state[sg].next_sglist = 0;
+               sgdma->sg_state[sg].bytes_read = 0;
+               sgdma->sg_state[sg].queued_sglist = 0;
+               sgdma->sg_state[sg].csr = 0;
+               sgdma->sg_state[sg].callback = NULL;
+               sgdma->sg_state[sg].arg = NULL;
+       }
+
+       omap24xxcam_dma_init(&sgdma->dma, base);
+       setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
+}
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
new file mode 100644 (file)
index 0000000..682d402
--- /dev/null
@@ -0,0 +1,1908 @@
+/*
+ * drivers/media/video/omap24xxcam.c
+ *
+ * OMAP 2 camera block driver.
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007-2008 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h>         /* needed for videobufs */
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+#include "omap24xxcam.h"
+
+#define OMAP24XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
+
+#define RESET_TIMEOUT_NS 10000
+
+static void omap24xxcam_reset(struct omap24xxcam_device *cam);
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
+static int omap24xxcam_remove(struct platform_device *pdev);
+
+/* module parameters */
+static int video_nr = -1;      /* video device minor (-1 ==> auto assign) */
+/*
+ * Maximum amount of memory to use for capture buffers.
+ * Default is 4800KB, enough to double-buffer SXGA.
+ */
+static int capture_mem = 1280 * 960 * 2 * 2;
+
+static struct v4l2_int_device omap24xxcam;
+
+/*
+ *
+ * Clocks.
+ *
+ */
+
+static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
+{
+       if (cam->ick != NULL && !IS_ERR(cam->ick))
+               clk_put(cam->ick);
+       if (cam->fck != NULL && !IS_ERR(cam->fck))
+               clk_put(cam->fck);
+
+       cam->ick = cam->fck = NULL;
+}
+
+static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
+{
+       int rval = 0;
+
+       cam->fck = clk_get(cam->dev, "cam_fck");
+       if (IS_ERR(cam->fck)) {
+               dev_err(cam->dev, "can't get cam_fck");
+               rval = PTR_ERR(cam->fck);
+               omap24xxcam_clock_put(cam);
+               return rval;
+       }
+
+       cam->ick = clk_get(cam->dev, "cam_ick");
+       if (IS_ERR(cam->ick)) {
+               dev_err(cam->dev, "can't get cam_ick");
+               rval = PTR_ERR(cam->ick);
+               omap24xxcam_clock_put(cam);
+       }
+
+       return rval;
+}
+
+static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
+{
+       clk_enable(cam->fck);
+       clk_enable(cam->ick);
+}
+
+static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
+{
+       clk_disable(cam->fck);
+       clk_disable(cam->ick);
+}
+
+/*
+ *
+ * Camera core
+ *
+ */
+
+/*
+ * Set xclk.
+ *
+ * To disable xclk, use value zero.
+ */
+static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
+                                     u32 xclk)
+{
+       if (xclk) {
+               u32 divisor = CAM_MCLK / xclk;
+
+               if (divisor == 1)
+                       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+                                           CC_CTRL_XCLK,
+                                           CC_CTRL_XCLK_DIV_BYPASS);
+               else
+                       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+                                           CC_CTRL_XCLK, divisor);
+       } else
+               omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
+                                   CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
+}
+
+static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
+{
+       /*
+        * Setting the camera core AUTOIDLE bit causes problems with frame
+        * synchronization, so we will clear the AUTOIDLE bit instead.
+        */
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
+                           CC_SYSCONFIG_AUTOIDLE);
+
+       /* program the camera interface DMA packet size */
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
+                           CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
+
+       /* enable camera core error interrupts */
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
+                           CC_IRQENABLE_FW_ERR_IRQ
+                           | CC_IRQENABLE_FSC_ERR_IRQ
+                           | CC_IRQENABLE_SSC_ERR_IRQ
+                           | CC_IRQENABLE_FIFO_OF_IRQ);
+}
+
+/*
+ * Enable the camera core.
+ *
+ * Data transfer to the camera DMA starts from next starting frame.
+ */
+static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
+{
+
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+                           cam->cc_ctrl);
+}
+
+/*
+ * Disable camera core.
+ *
+ * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
+ * core internal state machines will be reset. Use
+ * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
+ * frame completely.
+ */
+static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
+{
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
+                           CC_CTRL_CC_RST);
+}
+
+/* Interrupt service routine for camera core interrupts. */
+static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
+{
+       u32 cc_irqstatus;
+       const u32 cc_irqstatus_err =
+               CC_IRQSTATUS_FW_ERR_IRQ
+               | CC_IRQSTATUS_FSC_ERR_IRQ
+               | CC_IRQSTATUS_SSC_ERR_IRQ
+               | CC_IRQSTATUS_FIFO_UF_IRQ
+               | CC_IRQSTATUS_FIFO_OF_IRQ;
+
+       cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
+                                         CC_IRQSTATUS);
+       omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
+                           cc_irqstatus);
+
+       if (cc_irqstatus & cc_irqstatus_err
+           && !atomic_read(&cam->in_reset)) {
+               dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
+                       cc_irqstatus);
+               omap24xxcam_reset(cam);
+       }
+}
+
+/*
+ *
+ * videobuf_buffer handling.
+ *
+ * Memory for mmapped videobuf_buffers is not allocated
+ * conventionally, but by several kmalloc allocations and then
+ * creating the scatterlist on our own. User-space buffers are handled
+ * normally.
+ *
+ */
+
+/*
+ * Free the memory-mapped buffer memory allocated for a
+ * videobuf_buffer and the associated scatterlist.
+ */
+static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+       size_t alloc_size;
+       struct page *page;
+       int i;
+
+       if (dma->sglist == NULL)
+               return;
+
+       i = dma->sglen;
+       while (i) {
+               i--;
+               alloc_size = sg_dma_len(&dma->sglist[i]);
+               page = sg_page(&dma->sglist[i]);
+               do {
+                       ClearPageReserved(page++);
+               } while (alloc_size -= PAGE_SIZE);
+               __free_pages(sg_page(&dma->sglist[i]),
+                            get_order(sg_dma_len(&dma->sglist[i])));
+       }
+
+       kfree(dma->sglist);
+       dma->sglist = NULL;
+}
+
+/* Release all memory related to the videobuf_queue. */
+static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
+{
+       int i;
+
+       mutex_lock(&vbq->vb_lock);
+
+       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+               if (NULL == vbq->bufs[i])
+                       continue;
+               if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
+                       continue;
+               vbq->ops->buf_release(vbq, vbq->bufs[i]);
+               omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+               kfree(vbq->bufs[i]);
+               vbq->bufs[i] = NULL;
+       }
+
+       mutex_unlock(&vbq->vb_lock);
+
+       videobuf_mmap_free(vbq);
+}
+
+/*
+ * Allocate physically as contiguous as possible buffer for video
+ * frame and allocate and build DMA scatter-gather list for it.
+ */
+static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
+{
+       unsigned int order;
+       size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
+       struct page *page;
+       int max_pages, err = 0, i = 0;
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+       /*
+        * allocate maximum size scatter-gather list. Note this is
+        * overhead. We may not use as many entries as we allocate
+        */
+       max_pages = vb->bsize >> PAGE_SHIFT;
+       dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
+       if (dma->sglist == NULL) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       while (size) {
+               order = get_order(size);
+               /*
+                * do not over-allocate even if we would get larger
+                * contiguous chunk that way
+                */
+               if ((PAGE_SIZE << order) > size)
+                       order--;
+
+               /* try to allocate as many contiguous pages as possible */
+               page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+               /* if allocation fails, try to allocate smaller amount */
+               while (page == NULL) {
+                       order--;
+                       page = alloc_pages(GFP_KERNEL | GFP_DMA, order);
+                       if (page == NULL && !order) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+               }
+               size -= (PAGE_SIZE << order);
+
+               /* append allocated chunk of pages into scatter-gather list */
+               sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
+               dma->sglen++;
+               i++;
+
+               alloc_size = (PAGE_SIZE << order);
+
+               /* clear pages before giving them to user space */
+               memset(page_address(page), 0, alloc_size);
+
+               /* mark allocated pages reserved */
+               do {
+                       SetPageReserved(page++);
+               } while (alloc_size -= PAGE_SIZE);
+       }
+       /*
+        * REVISIT: not fully correct to assign nr_pages == sglen but
+        * video-buf is passing nr_pages for e.g. unmap_sg calls
+        */
+       dma->nr_pages = dma->sglen;
+       dma->direction = PCI_DMA_FROMDEVICE;
+
+       return 0;
+
+out:
+       omap24xxcam_vbq_free_mmap_buffer(vb);
+       return err;
+}
+
+static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
+                                             unsigned int count)
+{
+       int i, err = 0;
+       struct omap24xxcam_fh *fh =
+               container_of(vbq, struct omap24xxcam_fh, vbq);
+
+       mutex_lock(&vbq->vb_lock);
+
+       for (i = 0; i < count; i++) {
+               err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
+               if (err)
+                       goto out;
+               dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
+                       videobuf_to_dma(vbq->bufs[i])->sglen, i);
+       }
+
+       mutex_unlock(&vbq->vb_lock);
+
+       return 0;
+out:
+       while (i) {
+               i--;
+               omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
+       }
+
+       mutex_unlock(&vbq->vb_lock);
+
+       return err;
+}
+
+/*
+ * This routine is called from interrupt context when a scatter-gather DMA
+ * transfer of a videobuf_buffer completes.
+ */
+static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
+                                    u32 csr, void *arg)
+{
+       struct omap24xxcam_device *cam =
+               container_of(sgdma, struct omap24xxcam_device, sgdma);
+       struct omap24xxcam_fh *fh = cam->streaming->private_data;
+       struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
+       const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
+               | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
+               | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+       if (--cam->sgdma_in_queue == 0)
+               omap24xxcam_core_disable(cam);
+       spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+       do_gettimeofday(&vb->ts);
+       vb->field_count = atomic_add_return(2, &fh->field_count);
+       if (csr & csr_error) {
+               vb->state = VIDEOBUF_ERROR;
+               if (!atomic_read(&fh->cam->in_reset)) {
+                       dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
+                       omap24xxcam_reset(cam);
+               }
+       } else
+               vb->state = VIDEOBUF_DONE;
+       wake_up(&vb->done);
+}
+
+static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
+                                   struct videobuf_buffer *vb)
+{
+       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+       /* wait for buffer, especially to get out of the sgdma queue */
+       videobuf_waiton(vb, 0, 0);
+       if (vb->memory == V4L2_MEMORY_MMAP) {
+               dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
+                            dma->direction);
+               dma->direction = DMA_NONE;
+       } else {
+               videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
+               videobuf_dma_free(videobuf_to_dma(vb));
+       }
+
+       vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Limit the number of available kernel image capture buffers based on the
+ * number requested, the currently selected image size, and the maximum
+ * amount of memory permitted for kernel capture buffers.
+ */
+static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
+                                unsigned int *size)
+{
+       struct omap24xxcam_fh *fh = vbq->priv_data;
+
+       if (*cnt <= 0)
+               *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
+
+       if (*cnt > VIDEO_MAX_FRAME)
+               *cnt = VIDEO_MAX_FRAME;
+
+       *size = fh->pix.sizeimage;
+
+       /* accessing fh->cam->capture_mem is ok, it's constant */
+       while (*size * *cnt > fh->cam->capture_mem)
+               (*cnt)--;
+
+       return 0;
+}
+
+static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
+                                 struct videobuf_dmabuf *dma)
+{
+       int err = 0;
+
+       dma->direction = PCI_DMA_FROMDEVICE;
+       if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
+               kfree(dma->sglist);
+               dma->sglist = NULL;
+               dma->sglen = 0;
+               err = -EIO;
+       }
+
+       return err;
+}
+
+static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
+                                  struct videobuf_buffer *vb,
+                                  enum v4l2_field field)
+{
+       struct omap24xxcam_fh *fh = vbq->priv_data;
+       int err = 0;
+
+       /*
+        * Accessing pix here is okay since it's constant while
+        * streaming is on (and we only get called then).
+        */
+       if (vb->baddr) {
+               /* This is a userspace buffer. */
+               if (fh->pix.sizeimage > vb->bsize) {
+                       /* The buffer isn't big enough. */
+                       err = -EINVAL;
+               } else
+                       vb->size = fh->pix.sizeimage;
+       } else {
+               if (vb->state != VIDEOBUF_NEEDS_INIT) {
+                       /*
+                        * We have a kernel bounce buffer that has
+                        * already been allocated.
+                        */
+                       if (fh->pix.sizeimage > vb->size) {
+                               /*
+                                * The image size has been changed to
+                                * a larger size since this buffer was
+                                * allocated, so we need to free and
+                                * reallocate it.
+                                */
+                               omap24xxcam_vbq_release(vbq, vb);
+                               vb->size = fh->pix.sizeimage;
+                       }
+               } else {
+                       /* We need to allocate a new kernel bounce buffer. */
+                       vb->size = fh->pix.sizeimage;
+               }
+       }
+
+       if (err)
+               return err;
+
+       vb->width = fh->pix.width;
+       vb->height = fh->pix.height;
+       vb->field = field;
+
+       if (vb->state == VIDEOBUF_NEEDS_INIT) {
+               if (vb->memory == V4L2_MEMORY_MMAP)
+                       /*
+                        * we have built the scatter-gather list by ourself so
+                        * do the scatter-gather mapping as well
+                        */
+                       err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
+               else
+                       err = videobuf_iolock(vbq, vb, NULL);
+       }
+
+       if (!err)
+               vb->state = VIDEOBUF_PREPARED;
+       else
+               omap24xxcam_vbq_release(vbq, vb);
+
+       return err;
+}
+
+static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
+                                 struct videobuf_buffer *vb)
+{
+       struct omap24xxcam_fh *fh = vbq->priv_data;
+       struct omap24xxcam_device *cam = fh->cam;
+       enum videobuf_state state = vb->state;
+       unsigned long flags;
+       int err;
+
+       /*
+        * FIXME: We're marking the buffer active since we have no
+        * pretty way of marking it active exactly when the
+        * scatter-gather transfer starts.
+        */
+       vb->state = VIDEOBUF_ACTIVE;
+
+       err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
+                                     videobuf_to_dma(vb)->sglist,
+                                     videobuf_to_dma(vb)->sglen, vb->size,
+                                     omap24xxcam_vbq_complete, vb);
+
+       if (!err) {
+               spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+               if (++cam->sgdma_in_queue == 1
+                   && !atomic_read(&cam->in_reset))
+                       omap24xxcam_core_enable(cam);
+               spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+       } else {
+               /*
+                * Oops. We're not supposed to get any errors here.
+                * The only way we could get an error is if we ran out
+                * of scatter-gather DMA slots, but we are supposed to
+                * have at least as many scatter-gather DMA slots as
+                * video buffers so that can't happen.
+                */
+               dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
+               dev_err(cam->dev, "likely a bug in the driver!\n");
+               vb->state = state;
+       }
+}
+
+static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
+       .buf_setup   = omap24xxcam_vbq_setup,
+       .buf_prepare = omap24xxcam_vbq_prepare,
+       .buf_queue   = omap24xxcam_vbq_queue,
+       .buf_release = omap24xxcam_vbq_release,
+};
+
+/*
+ *
+ * OMAP main camera system
+ *
+ */
+
+/*
+ * Reset camera block to power-on state.
+ */
+static void omap24xxcam_poweron_reset(const struct omap24xxcam_device *cam)
+{
+       int max_loop = RESET_TIMEOUT_NS;
+
+       /* Reset whole camera subsystem */
+       omap24xxcam_reg_out(cam->mmio_base,
+                           CAM_SYSCONFIG,
+                           CAM_SYSCONFIG_SOFTRESET);
+
+       /* Wait till it's finished */
+       while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+                & CAM_SYSSTATUS_RESETDONE)
+              && --max_loop) {
+               ndelay(1);
+       }
+
+       if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
+             & CAM_SYSSTATUS_RESETDONE))
+               dev_err(cam->dev, "camera soft reset timeout\n");
+}
+
+/*
+ * (Re)initialise the camera block.
+ */
+static void omap24xxcam_hwinit(const struct omap24xxcam_device *cam)
+{
+       omap24xxcam_poweron_reset(cam);
+
+       /* set the camera subsystem autoidle bit */
+       omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
+                           CAM_SYSCONFIG_AUTOIDLE);
+
+       /* set the camera MMU autoidle bit */
+       omap24xxcam_reg_out(cam->mmio_base,
+                           CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
+                           CAMMMU_SYSCONFIG_AUTOIDLE);
+
+       omap24xxcam_core_hwinit(cam);
+
+       omap24xxcam_dma_hwinit(&cam->sgdma.dma);
+}
+
+/*
+ * Callback for dma transfer stalling.
+ */
+static void omap24xxcam_stalled_dma_reset(unsigned long data)
+{
+       struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
+
+       if (!atomic_read(&cam->in_reset)) {
+               dev_dbg(cam->dev, "dma stalled, resetting camera\n");
+               omap24xxcam_reset(cam);
+       }
+}
+
+/*
+ * Stop capture. Mark we're doing a reset, stop DMA transfers and
+ * core. (No new scatter-gather transfers will be queued whilst
+ * in_reset is non-zero.)
+ *
+ * If omap24xxcam_capture_stop is called from several places at
+ * once, only the first call will have an effect. Similarly, the last
+ * call omap24xxcam_streaming_cont will have effect.
+ *
+ * Serialisation is ensured by using cam->core_enable_disable_lock.
+ */
+static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+       if (atomic_inc_return(&cam->in_reset) != 1) {
+               spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+               return;
+       }
+
+       omap24xxcam_core_disable(cam);
+
+       spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+
+       omap24xxcam_sgdma_sync(&cam->sgdma);
+}
+
+/*
+ * Reset and continue streaming.
+ *
+ * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
+ * register is supposed to be sufficient to recover from a camera
+ * interface error, but it doesn't seem to be enough. If we only do
+ * that then subsequent image captures are out of sync by either one
+ * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
+ * entire camera subsystem prevents the problem with frame
+ * synchronization.
+ */
+static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
+
+       if (atomic_read(&cam->in_reset) != 1)
+               goto out;
+
+       omap24xxcam_hwinit(cam);
+
+       omap24xxcam_sensor_if_enable(cam);
+
+       omap24xxcam_sgdma_process(&cam->sgdma);
+
+       if (cam->sgdma_in_queue)
+               omap24xxcam_core_enable(cam);
+
+out:
+       atomic_dec(&cam->in_reset);
+       spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
+}
+
+static ssize_t
+omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct omap24xxcam_device *cam = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", cam->streaming ?  "active" : "inactive");
+}
+static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
+
+/*
+ * Stop capture and restart it. I.e. reset the camera during use.
+ */
+static void omap24xxcam_reset(struct omap24xxcam_device *cam)
+{
+       omap24xxcam_capture_stop(cam);
+       omap24xxcam_capture_cont(cam);
+}
+
+/*
+ * The main interrupt handler.
+ */
+static irqreturn_t omap24xxcam_isr(int irq, void *arg)
+{
+       struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
+       u32 irqstatus;
+       unsigned int irqhandled = 0;
+
+       irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
+
+       if (irqstatus &
+           (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
+            | CAM_IRQSTATUS_DMA_IRQ0)) {
+               omap24xxcam_dma_isr(&cam->sgdma.dma);
+               irqhandled = 1;
+       }
+       if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
+               omap24xxcam_core_isr(cam);
+               irqhandled = 1;
+       }
+       if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
+               dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
+
+       return IRQ_RETVAL(irqhandled);
+}
+
+/*
+ *
+ * Sensor handling.
+ *
+ */
+
+/*
+ * Enable the external sensor interface. Try to negotiate interface
+ * parameters with the sensor and start using the new ones. The calls
+ * to sensor_if_enable and sensor_if_disable need not to be balanced.
+ */
+static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
+{
+       int rval;
+       struct v4l2_ifparm p;
+
+       rval = vidioc_int_g_ifparm(cam->sdev, &p);
+       if (rval) {
+               dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
+               return rval;
+       }
+
+       cam->if_type = p.if_type;
+
+       cam->cc_ctrl = CC_CTRL_CC_EN;
+
+       switch (p.if_type) {
+       case V4L2_IF_TYPE_BT656:
+               if (p.u.bt656.frame_start_on_rising_vs)
+                       cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
+               if (p.u.bt656.bt_sync_correct)
+                       cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
+               if (p.u.bt656.swap)
+                       cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
+               if (p.u.bt656.latch_clk_inv)
+                       cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
+               if (p.u.bt656.nobt_hs_inv)
+                       cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
+               if (p.u.bt656.nobt_vs_inv)
+                       cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
+
+               switch (p.u.bt656.mode) {
+               case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
+                       cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
+                       break;
+               case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
+                       cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
+                       break;
+               case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
+                       cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
+                       break;
+               case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
+                       cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
+                       break;
+               case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
+                       cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
+                       break;
+               default:
+                       dev_err(cam->dev,
+                               "bt656 interface mode %d not supported\n",
+                               p.u.bt656.mode);
+                       return -EINVAL;
+               }
+               /*
+                * The clock rate that the sensor wants has changed.
+                * We have to adjust the xclk from OMAP 2 side to
+                * match the sensor's wish as closely as possible.
+                */
+               if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
+                       u32 xclk = p.u.bt656.clock_curr;
+                       u32 divisor;
+
+                       if (xclk == 0)
+                               return -EINVAL;
+
+                       if (xclk > CAM_MCLK)
+                               xclk = CAM_MCLK;
+
+                       divisor = CAM_MCLK / xclk;
+                       if (divisor * xclk < CAM_MCLK)
+                               divisor++;
+                       if (CAM_MCLK / divisor < p.u.bt656.clock_min
+                           && divisor > 1)
+                               divisor--;
+                       if (divisor > 30)
+                               divisor = 30;
+
+                       xclk = CAM_MCLK / divisor;
+
+                       if (xclk < p.u.bt656.clock_min
+                           || xclk > p.u.bt656.clock_max)
+                               return -EINVAL;
+
+                       cam->if_u.bt656.xclk = xclk;
+               }
+               omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
+               break;
+       default:
+               /* FIXME: how about other interfaces? */
+               dev_err(cam->dev, "interface type %d not supported\n",
+                       p.if_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
+{
+       switch (cam->if_type) {
+       case V4L2_IF_TYPE_BT656:
+               omap24xxcam_core_xclk_set(cam, 0);
+               break;
+       }
+}
+
+/*
+ * Initialise the sensor hardware.
+ */
+static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
+{
+       int err = 0;
+       struct v4l2_int_device *sdev = cam->sdev;
+
+       omap24xxcam_clock_on(cam);
+       err = omap24xxcam_sensor_if_enable(cam);
+       if (err) {
+               dev_err(cam->dev, "sensor interface could not be enabled at "
+                       "initialisation, %d\n", err);
+               cam->sdev = NULL;
+               goto out;
+       }
+
+       /* power up sensor during sensor initialization */
+       vidioc_int_s_power(sdev, 1);
+
+       err = vidioc_int_dev_init(sdev);
+       if (err) {
+               dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
+               /* Sensor init failed --- it's nonexistent to us! */
+               cam->sdev = NULL;
+               goto out;
+       }
+
+       dev_info(cam->dev, "sensor is %s\n", sdev->name);
+
+out:
+       omap24xxcam_sensor_if_disable(cam);
+       omap24xxcam_clock_off(cam);
+
+       vidioc_int_s_power(sdev, 0);
+
+       return err;
+}
+
+static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
+{
+       if (cam->sdev)
+               vidioc_int_dev_exit(cam->sdev);
+}
+
+static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
+{
+       omap24xxcam_sensor_if_disable(cam);
+       omap24xxcam_clock_off(cam);
+       vidioc_int_s_power(cam->sdev, 0);
+}
+
+/*
+ * Power-up and configure camera sensor. It's ready for capturing now.
+ */
+static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
+{
+       int rval;
+
+       omap24xxcam_clock_on(cam);
+
+       omap24xxcam_sensor_if_enable(cam);
+
+       rval = vidioc_int_s_power(cam->sdev, 1);
+       if (rval)
+               goto out;
+
+       rval = vidioc_int_init(cam->sdev);
+       if (rval)
+               goto out;
+
+       return 0;
+
+out:
+       omap24xxcam_sensor_disable(cam);
+
+       return rval;
+}
+
+static void omap24xxcam_sensor_reset_work(struct work_struct *work)
+{
+       struct omap24xxcam_device *cam =
+               container_of(work, struct omap24xxcam_device,
+                            sensor_reset_work);
+
+       if (atomic_read(&cam->reset_disable))
+               return;
+
+       omap24xxcam_capture_stop(cam);
+
+       if (vidioc_int_reset(cam->sdev) == 0) {
+               vidioc_int_init(cam->sdev);
+       } else {
+               /* Can't reset it by vidioc_int_reset. */
+               omap24xxcam_sensor_disable(cam);
+               omap24xxcam_sensor_enable(cam);
+       }
+
+       omap24xxcam_capture_cont(cam);
+}
+
+/*
+ *
+ * IOCTL interface.
+ *
+ */
+
+static int vidioc_querycap(struct file *file, void *fh,
+                          struct v4l2_capability *cap)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+
+       strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
+       cap->version = OMAP24XXCAM_VERSION;
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       rval = vidioc_int_enum_fmt_cap(cam->sdev, f);
+
+       return rval;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       rval = vidioc_int_g_fmt_cap(cam->sdev, f);
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+                               struct v4l2_format *f)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       rval = vidioc_int_s_fmt_cap(cam->sdev, f);
+
+out:
+       mutex_unlock(&cam->mutex);
+
+       if (!rval) {
+               mutex_lock(&ofh->vbq.vb_lock);
+               ofh->pix = f->fmt.pix;
+               mutex_unlock(&ofh->vbq.vb_lock);
+       }
+
+       memset(f, 0, sizeof(*f));
+       vidioc_g_fmt_vid_cap(file, fh, f);
+
+       return rval;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+                                 struct v4l2_format *f)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       rval = vidioc_int_try_fmt_cap(cam->sdev, f);
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+                         struct v4l2_requestbuffers *b)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming) {
+               mutex_unlock(&cam->mutex);
+               return -EBUSY;
+       }
+
+       omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+       mutex_unlock(&cam->mutex);
+
+       rval = videobuf_reqbufs(&ofh->vbq, b);
+
+       /*
+        * Either videobuf_reqbufs failed or the buffers are not
+        * memory-mapped (which would need special attention).
+        */
+       if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
+               goto out;
+
+       rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
+       if (rval)
+               omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
+
+out:
+       return rval;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+                          struct v4l2_buffer *b)
+{
+       struct omap24xxcam_fh *ofh = fh;
+
+       return videobuf_querybuf(&ofh->vbq, b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap24xxcam_fh *ofh = fh;
+
+       return videobuf_qbuf(&ofh->vbq, b);
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       struct videobuf_buffer *vb;
+       int rval;
+
+videobuf_dqbuf_again:
+       rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
+       if (rval)
+               goto out;
+
+       vb = ofh->vbq.bufs[b->index];
+
+       mutex_lock(&cam->mutex);
+       /* _needs_reset returns -EIO if reset is required. */
+       rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
+       mutex_unlock(&cam->mutex);
+       if (rval == -EIO)
+               schedule_work(&cam->sensor_reset_work);
+       else
+               rval = 0;
+
+out:
+       /*
+        * This is a hack. We don't want to show -EIO to the user
+        * space. Requeue the buffer and try again if we're not doing
+        * this in non-blocking mode.
+        */
+       if (rval == -EIO) {
+               videobuf_qbuf(&ofh->vbq, b);
+               if (!(file->f_flags & O_NONBLOCK))
+                       goto videobuf_dqbuf_again;
+               /*
+                * We don't have a videobuf_buffer now --- maybe next
+                * time...
+                */
+               rval = -EAGAIN;
+       }
+
+       return rval;
+}
+
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       rval = omap24xxcam_sensor_if_enable(cam);
+       if (rval) {
+               dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
+               goto out;
+       }
+
+       rval = videobuf_streamon(&ofh->vbq);
+       if (!rval) {
+               cam->streaming = file;
+               sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+       }
+
+out:
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       struct videobuf_queue *q = &ofh->vbq;
+       int rval;
+
+       atomic_inc(&cam->reset_disable);
+
+       flush_scheduled_work();
+
+       rval = videobuf_streamoff(q);
+       if (!rval) {
+               mutex_lock(&cam->mutex);
+               cam->streaming = NULL;
+               mutex_unlock(&cam->mutex);
+               sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+       }
+
+       atomic_dec(&cam->reset_disable);
+
+       return rval;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh,
+                            struct v4l2_input *inp)
+{
+       if (inp->index > 0)
+               return -EINVAL;
+
+       strlcpy(inp->name, "camera", sizeof(inp->name));
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+       if (i > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+                           struct v4l2_queryctrl *a)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       rval = vidioc_int_queryctrl(cam->sdev, a);
+
+       return rval;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh,
+                        struct v4l2_control *a)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       rval = vidioc_int_g_ctrl(cam->sdev, a);
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh,
+                        struct v4l2_control *a)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       mutex_lock(&cam->mutex);
+       rval = vidioc_int_s_ctrl(cam->sdev, a);
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+                        struct v4l2_streamparm *a) {
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&cam->mutex);
+       rval = vidioc_int_g_parm(cam->sdev, a);
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+                        struct v4l2_streamparm *a)
+{
+       struct omap24xxcam_fh *ofh = fh;
+       struct omap24xxcam_device *cam = ofh->cam;
+       struct v4l2_streamparm old_streamparm;
+       int rval;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming) {
+               rval = -EBUSY;
+               goto out;
+       }
+
+       old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
+       if (rval)
+               goto out;
+
+       rval = vidioc_int_s_parm(cam->sdev, a);
+       if (rval)
+               goto out;
+
+       rval = omap24xxcam_sensor_if_enable(cam);
+       /*
+        * Revert to old streaming parameters if enabling sensor
+        * interface with the new ones failed.
+        */
+       if (rval)
+               vidioc_int_s_parm(cam->sdev, &old_streamparm);
+
+out:
+       mutex_unlock(&cam->mutex);
+
+       return rval;
+}
+
+/*
+ *
+ * File operations.
+ *
+ */
+
+static unsigned int omap24xxcam_poll(struct file *file,
+                                    struct poll_table_struct *wait)
+{
+       struct omap24xxcam_fh *fh = file->private_data;
+       struct omap24xxcam_device *cam = fh->cam;
+       struct videobuf_buffer *vb;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming != file) {
+               mutex_unlock(&cam->mutex);
+               return POLLERR;
+       }
+       mutex_unlock(&cam->mutex);
+
+       mutex_lock(&fh->vbq.vb_lock);
+       if (list_empty(&fh->vbq.stream)) {
+               mutex_unlock(&fh->vbq.vb_lock);
+               return POLLERR;
+       }
+       vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
+       mutex_unlock(&fh->vbq.vb_lock);
+
+       poll_wait(file, &vb->done, wait);
+
+       if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
+               return POLLIN | POLLRDNORM;
+
+       return 0;
+}
+
+static int omap24xxcam_mmap_buffers(struct file *file,
+                                   struct vm_area_struct *vma)
+{
+       struct omap24xxcam_fh *fh = file->private_data;
+       struct omap24xxcam_device *cam = fh->cam;
+       struct videobuf_queue *vbq = &fh->vbq;
+       unsigned int first, last, size, i, j;
+       int err = 0;
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming) {
+               mutex_unlock(&cam->mutex);
+               return -EBUSY;
+       }
+       mutex_unlock(&cam->mutex);
+       mutex_lock(&vbq->vb_lock);
+
+       /* look for first buffer to map */
+       for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+               if (NULL == vbq->bufs[first])
+                       continue;
+               if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
+                       continue;
+               if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+                       break;
+       }
+
+       /* look for last buffer to map */
+       for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+               if (NULL == vbq->bufs[last])
+                       continue;
+               if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
+                       continue;
+               size += vbq->bufs[last]->bsize;
+               if (size == (vma->vm_end - vma->vm_start))
+                       break;
+       }
+
+       size = 0;
+       for (i = first; i <= last; i++) {
+               struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
+
+               for (j = 0; j < dma->sglen; j++) {
+                       err = remap_pfn_range(
+                               vma, vma->vm_start + size,
+                               page_to_pfn(sg_page(&dma->sglist[j])),
+                               sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
+                       if (err)
+                               goto out;
+                       size += sg_dma_len(&dma->sglist[j]);
+               }
+       }
+
+out:
+       mutex_unlock(&vbq->vb_lock);
+
+       return err;
+}
+
+static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct omap24xxcam_fh *fh = file->private_data;
+       int rval;
+
+       /* let the video-buf mapper check arguments and set-up structures */
+       rval = videobuf_mmap_mapper(&fh->vbq, vma);
+       if (rval)
+               return rval;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       /* do mapping to our allocated buffers */
+       rval = omap24xxcam_mmap_buffers(file, vma);
+       /*
+        * In case of error, free vma->vm_private_data allocated by
+        * videobuf_mmap_mapper.
+        */
+       if (rval)
+               kfree(vma->vm_private_data);
+
+       return rval;
+}
+
+static int omap24xxcam_open(struct inode *inode, struct file *file)
+{
+       int minor = iminor(inode);
+       struct omap24xxcam_device *cam = omap24xxcam.priv;
+       struct omap24xxcam_fh *fh;
+       struct v4l2_format format;
+
+       if (!cam || !cam->vfd || (cam->vfd->minor != minor))
+               return -ENODEV;
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL)
+               return -ENOMEM;
+
+       mutex_lock(&cam->mutex);
+       if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
+               mutex_unlock(&cam->mutex);
+               goto out_try_module_get;
+       }
+
+       if (atomic_inc_return(&cam->users) == 1) {
+               omap24xxcam_hwinit(cam);
+               if (omap24xxcam_sensor_enable(cam)) {
+                       mutex_unlock(&cam->mutex);
+                       goto out_omap24xxcam_sensor_enable;
+               }
+       }
+       mutex_unlock(&cam->mutex);
+
+       fh->cam = cam;
+       mutex_lock(&cam->mutex);
+       vidioc_int_g_fmt_cap(cam->sdev, &format);
+       mutex_unlock(&cam->mutex);
+       /* FIXME: how about fh->pix when there are more users? */
+       fh->pix = format.fmt.pix;
+
+       file->private_data = fh;
+
+       spin_lock_init(&fh->vbq_lock);
+
+       videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
+                               &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                               V4L2_FIELD_NONE,
+                               sizeof(struct videobuf_buffer), fh);
+
+       return 0;
+
+out_omap24xxcam_sensor_enable:
+       omap24xxcam_poweron_reset(cam);
+       module_put(cam->sdev->module);
+
+out_try_module_get:
+       kfree(fh);
+
+       return -ENODEV;
+}
+
+static int omap24xxcam_release(struct inode *inode, struct file *file)
+{
+       struct omap24xxcam_fh *fh = file->private_data;
+       struct omap24xxcam_device *cam = fh->cam;
+
+       atomic_inc(&cam->reset_disable);
+
+       flush_scheduled_work();
+
+       /* stop streaming capture */
+       videobuf_streamoff(&fh->vbq);
+
+       mutex_lock(&cam->mutex);
+       if (cam->streaming == file) {
+               cam->streaming = NULL;
+               mutex_unlock(&cam->mutex);
+               sysfs_notify(&cam->dev->kobj, NULL, "streaming");
+       } else {
+               mutex_unlock(&cam->mutex);
+       }
+
+       atomic_dec(&cam->reset_disable);
+
+       omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
+
+       /*
+        * Make sure the reset work we might have scheduled is not
+        * pending! It may be run *only* if we have users. (And it may
+        * not be scheduled anymore since streaming is already
+        * disabled.)
+        */
+       flush_scheduled_work();
+
+       mutex_lock(&cam->mutex);
+       if (atomic_dec_return(&cam->users) == 0) {
+               omap24xxcam_sensor_disable(cam);
+               omap24xxcam_poweron_reset(cam);
+       }
+       mutex_unlock(&cam->mutex);
+
+       file->private_data = NULL;
+
+       module_put(cam->sdev->module);
+       kfree(fh);
+
+       return 0;
+}
+
+static struct file_operations omap24xxcam_fops = {
+       .llseek  = no_llseek,
+       .ioctl   = video_ioctl2,
+       .poll    = omap24xxcam_poll,
+       .mmap    = omap24xxcam_mmap,
+       .open    = omap24xxcam_open,
+       .release = omap24xxcam_release,
+};
+
+/*
+ *
+ * Power management.
+ *
+ */
+
+#ifdef CONFIG_PM
+static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+       if (atomic_read(&cam->users) == 0)
+               return 0;
+
+       if (!atomic_read(&cam->reset_disable))
+               omap24xxcam_capture_stop(cam);
+
+       omap24xxcam_sensor_disable(cam);
+       omap24xxcam_poweron_reset(cam);
+
+       return 0;
+}
+
+static int omap24xxcam_resume(struct platform_device *pdev)
+{
+       struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+       if (atomic_read(&cam->users) == 0)
+               return 0;
+
+       omap24xxcam_hwinit(cam);
+       omap24xxcam_sensor_enable(cam);
+
+       if (!atomic_read(&cam->reset_disable))
+               omap24xxcam_capture_cont(cam);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
+       .vidioc_querycap        = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+       .vidioc_reqbufs         = vidioc_reqbufs,
+       .vidioc_querybuf        = vidioc_querybuf,
+       .vidioc_qbuf            = vidioc_qbuf,
+       .vidioc_dqbuf           = vidioc_dqbuf,
+       .vidioc_streamon        = vidioc_streamon,
+       .vidioc_streamoff       = vidioc_streamoff,
+       .vidioc_enum_input      = vidioc_enum_input,
+       .vidioc_g_input         = vidioc_g_input,
+       .vidioc_s_input         = vidioc_s_input,
+       .vidioc_queryctrl       = vidioc_queryctrl,
+       .vidioc_g_ctrl          = vidioc_g_ctrl,
+       .vidioc_s_ctrl          = vidioc_s_ctrl,
+       .vidioc_g_parm          = vidioc_g_parm,
+       .vidioc_s_parm          = vidioc_s_parm,
+};
+
+/*
+ *
+ * Camera device (i.e. /dev/video).
+ *
+ */
+
+static int omap24xxcam_device_register(struct v4l2_int_device *s)
+{
+       struct omap24xxcam_device *cam = s->u.slave->master->priv;
+       struct video_device *vfd;
+       int rval;
+
+       /* We already have a slave. */
+       if (cam->sdev)
+               return -EBUSY;
+
+       cam->sdev = s;
+
+       if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
+               dev_err(cam->dev, "could not register sysfs entry\n");
+               rval = -EBUSY;
+               goto err;
+       }
+
+       /* initialize the video_device struct */
+       vfd = cam->vfd = video_device_alloc();
+       if (!vfd) {
+               dev_err(cam->dev, "could not allocate video device struct\n");
+               rval = -ENOMEM;
+               goto err;
+       }
+       vfd->release = video_device_release;
+
+       vfd->parent = cam->dev;
+
+       strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
+       vfd->vfl_type            = VID_TYPE_CAPTURE | VID_TYPE_CHROMAKEY;
+       vfd->fops                = &omap24xxcam_fops;
+       vfd->priv                = cam;
+       vfd->minor               = -1;
+       vfd->ioctl_ops           = &omap24xxcam_ioctl_fops;
+
+       omap24xxcam_hwinit(cam);
+
+       rval = omap24xxcam_sensor_init(cam);
+       if (rval)
+               goto err;
+
+       if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
+               dev_err(cam->dev, "could not register V4L device\n");
+               vfd->minor = -1;
+               rval = -EBUSY;
+               goto err;
+       }
+
+       omap24xxcam_poweron_reset(cam);
+
+       dev_info(cam->dev, "registered device video%d\n", vfd->minor);
+
+       return 0;
+
+err:
+       omap24xxcam_device_unregister(s);
+
+       return rval;
+}
+
+static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
+{
+       struct omap24xxcam_device *cam = s->u.slave->master->priv;
+
+       omap24xxcam_sensor_exit(cam);
+
+       if (cam->vfd) {
+               if (cam->vfd->minor == -1) {
+                       /*
+                        * The device was never registered, so release the
+                        * video_device struct directly.
+                        */
+                       video_device_release(cam->vfd);
+               } else {
+                       /*
+                        * The unregister function will release the
+                        * video_device struct as well as
+                        * unregistering it.
+                        */
+                       video_unregister_device(cam->vfd);
+               }
+               cam->vfd = NULL;
+       }
+
+       device_remove_file(cam->dev, &dev_attr_streaming);
+
+       cam->sdev = NULL;
+}
+
+static struct v4l2_int_master omap24xxcam_master = {
+       .attach = omap24xxcam_device_register,
+       .detach = omap24xxcam_device_unregister,
+};
+
+static struct v4l2_int_device omap24xxcam = {
+       .module = THIS_MODULE,
+       .name   = CAM_NAME,
+       .type   = v4l2_int_type_master,
+       .u      = {
+               .master = &omap24xxcam_master
+       },
+};
+
+/*
+ *
+ * Driver initialisation and deinitialisation.
+ *
+ */
+
+static int __init omap24xxcam_probe(struct platform_device *pdev)
+{
+       struct omap24xxcam_device *cam;
+       struct resource *mem;
+       int irq;
+
+       cam = kzalloc(sizeof(*cam), GFP_KERNEL);
+       if (!cam) {
+               dev_err(&pdev->dev, "could not allocate memory\n");
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, cam);
+
+       cam->dev = &pdev->dev;
+
+       /*
+        * Impose a lower limit on the amount of memory allocated for
+        * capture. We require at least enough memory to double-buffer
+        * QVGA (300KB).
+        */
+       if (capture_mem < 320 * 240 * 2 * 2)
+               capture_mem = 320 * 240 * 2 * 2;
+       cam->capture_mem = capture_mem;
+
+       /* request the mem region for the camera registers */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(cam->dev, "no mem resource?\n");
+               goto err;
+       }
+       if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+                               pdev->name)) {
+               dev_err(cam->dev,
+                       "cannot reserve camera register I/O region\n");
+               goto err;
+       }
+       cam->mmio_base_phys = mem->start;
+       cam->mmio_size = (mem->end - mem->start) + 1;
+
+       /* map the region */
+       cam->mmio_base = (unsigned long)
+               ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+       if (!cam->mmio_base) {
+               dev_err(cam->dev, "cannot map camera register I/O region\n");
+               goto err;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(cam->dev, "no irq for camera?\n");
+               goto err;
+       }
+
+       /* install the interrupt service routine */
+       if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
+               dev_err(cam->dev,
+                       "could not install interrupt service routine\n");
+               goto err;
+       }
+       cam->irq = irq;
+
+       if (omap24xxcam_clock_get(cam))
+               goto err;
+
+       INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
+
+       mutex_init(&cam->mutex);
+       spin_lock_init(&cam->core_enable_disable_lock);
+
+       omap24xxcam_sgdma_init(&cam->sgdma,
+                              cam->mmio_base + CAMDMA_REG_OFFSET,
+                              omap24xxcam_stalled_dma_reset,
+                              (unsigned long)cam);
+
+       omap24xxcam.priv = cam;
+
+       if (v4l2_int_device_register(&omap24xxcam))
+               goto err;
+
+       return 0;
+
+err:
+       omap24xxcam_remove(pdev);
+       return -ENODEV;
+}
+
+static int omap24xxcam_remove(struct platform_device *pdev)
+{
+       struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
+
+       if (!cam)
+               return 0;
+
+       if (omap24xxcam.priv != NULL)
+               v4l2_int_device_unregister(&omap24xxcam);
+       omap24xxcam.priv = NULL;
+
+       omap24xxcam_clock_put(cam);
+
+       if (cam->irq) {
+               free_irq(cam->irq, cam);
+               cam->irq = 0;
+       }
+
+       if (cam->mmio_base) {
+               iounmap((void *)cam->mmio_base);
+               cam->mmio_base = 0;
+       }
+
+       if (cam->mmio_base_phys) {
+               release_mem_region(cam->mmio_base_phys, cam->mmio_size);
+               cam->mmio_base_phys = 0;
+       }
+
+       kfree(cam);
+
+       return 0;
+}
+
+static struct platform_driver omap24xxcam_driver = {
+       .probe   = omap24xxcam_probe,
+       .remove  = omap24xxcam_remove,
+#ifdef CONFIG_PM
+       .suspend = omap24xxcam_suspend,
+       .resume  = omap24xxcam_resume,
+#endif
+       .driver  = {
+               .name = CAM_NAME,
+       },
+};
+
+/*
+ *
+ * Module initialisation and deinitialisation
+ *
+ */
+
+static int __init omap24xxcam_init(void)
+{
+       return platform_driver_register(&omap24xxcam_driver);
+}
+
+static void __exit omap24xxcam_cleanup(void)
+{
+       platform_driver_unregister(&omap24xxcam_driver);
+}
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
+MODULE_LICENSE("GPL");
+module_param(video_nr, int, 0);
+MODULE_PARM_DESC(video_nr,
+                "Minor number for video device (-1 ==> auto assign)");
+module_param(capture_mem, int, 0);
+MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
+                "buffers (default 4800kiB)");
+
+module_init(omap24xxcam_init);
+module_exit(omap24xxcam_cleanup);
diff --git a/drivers/media/video/omap24xxcam.h b/drivers/media/video/omap24xxcam.h
new file mode 100644 (file)
index 0000000..00d0e31
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * drivers/media/video/omap24xxcam.h
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from Andy Lowe <source@mvista.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef OMAP24XXCAM_H
+#define OMAP24XXCAM_H
+
+#include <media/videobuf-dma-sg.h>
+#include <media/v4l2-int-device.h>
+
+/*
+ *
+ * General driver related definitions.
+ *
+ */
+
+#define CAM_NAME                               "omap24xxcam"
+
+#define CAM_MCLK                               96000000
+
+/* number of bytes transferred per DMA request */
+#define DMA_THRESHOLD                          32
+
+/*
+ * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
+ * the camera DMA controller.
+ */
+#define NUM_CAMDMA_CHANNELS                    4
+
+/*
+ * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
+ * be queued. (We don't have any overlay sglists now.)
+ */
+#define NUM_SG_DMA                             (VIDEO_MAX_FRAME)
+
+/*
+ *
+ * Register definitions.
+ *
+ */
+
+/* subsystem register block offsets */
+#define CC_REG_OFFSET                          0x00000400
+#define CAMDMA_REG_OFFSET                      0x00000800
+#define CAMMMU_REG_OFFSET                      0x00000C00
+
+/* define camera subsystem register offsets */
+#define CAM_REVISION                           0x000
+#define CAM_SYSCONFIG                          0x010
+#define CAM_SYSSTATUS                          0x014
+#define CAM_IRQSTATUS                          0x018
+#define CAM_GPO                                        0x040
+#define CAM_GPI                                        0x050
+
+/* define camera core register offsets */
+#define CC_REVISION                            0x000
+#define CC_SYSCONFIG                           0x010
+#define CC_SYSSTATUS                           0x014
+#define CC_IRQSTATUS                           0x018
+#define CC_IRQENABLE                           0x01C
+#define CC_CTRL                                        0x040
+#define CC_CTRL_DMA                            0x044
+#define CC_CTRL_XCLK                           0x048
+#define CC_FIFODATA                            0x04C
+#define CC_TEST                                        0x050
+#define CC_GENPAR                              0x054
+#define CC_CCPFSCR                             0x058
+#define CC_CCPFECR                             0x05C
+#define CC_CCPLSCR                             0x060
+#define CC_CCPLECR                             0x064
+#define CC_CCPDFR                              0x068
+
+/* define camera dma register offsets */
+#define CAMDMA_REVISION                                0x000
+#define CAMDMA_IRQSTATUS_L0                    0x008
+#define CAMDMA_IRQSTATUS_L1                    0x00C
+#define CAMDMA_IRQSTATUS_L2                    0x010
+#define CAMDMA_IRQSTATUS_L3                    0x014
+#define CAMDMA_IRQENABLE_L0                    0x018
+#define CAMDMA_IRQENABLE_L1                    0x01C
+#define CAMDMA_IRQENABLE_L2                    0x020
+#define CAMDMA_IRQENABLE_L3                    0x024
+#define CAMDMA_SYSSTATUS                       0x028
+#define CAMDMA_OCP_SYSCONFIG                   0x02C
+#define CAMDMA_CAPS_0                          0x064
+#define CAMDMA_CAPS_2                          0x06C
+#define CAMDMA_CAPS_3                          0x070
+#define CAMDMA_CAPS_4                          0x074
+#define CAMDMA_GCR                             0x078
+#define CAMDMA_CCR(n)                          (0x080 + (n)*0x60)
+#define CAMDMA_CLNK_CTRL(n)                    (0x084 + (n)*0x60)
+#define CAMDMA_CICR(n)                         (0x088 + (n)*0x60)
+#define CAMDMA_CSR(n)                          (0x08C + (n)*0x60)
+#define CAMDMA_CSDP(n)                         (0x090 + (n)*0x60)
+#define CAMDMA_CEN(n)                          (0x094 + (n)*0x60)
+#define CAMDMA_CFN(n)                          (0x098 + (n)*0x60)
+#define CAMDMA_CSSA(n)                         (0x09C + (n)*0x60)
+#define CAMDMA_CDSA(n)                         (0x0A0 + (n)*0x60)
+#define CAMDMA_CSEI(n)                         (0x0A4 + (n)*0x60)
+#define CAMDMA_CSFI(n)                         (0x0A8 + (n)*0x60)
+#define CAMDMA_CDEI(n)                         (0x0AC + (n)*0x60)
+#define CAMDMA_CDFI(n)                         (0x0B0 + (n)*0x60)
+#define CAMDMA_CSAC(n)                         (0x0B4 + (n)*0x60)
+#define CAMDMA_CDAC(n)                         (0x0B8 + (n)*0x60)
+#define CAMDMA_CCEN(n)                         (0x0BC + (n)*0x60)
+#define CAMDMA_CCFN(n)                         (0x0C0 + (n)*0x60)
+#define CAMDMA_COLOR(n)                                (0x0C4 + (n)*0x60)
+
+/* define camera mmu register offsets */
+#define CAMMMU_REVISION                                0x000
+#define CAMMMU_SYSCONFIG                       0x010
+#define CAMMMU_SYSSTATUS                       0x014
+#define CAMMMU_IRQSTATUS                       0x018
+#define CAMMMU_IRQENABLE                       0x01C
+#define CAMMMU_WALKING_ST                      0x040
+#define CAMMMU_CNTL                            0x044
+#define CAMMMU_FAULT_AD                                0x048
+#define CAMMMU_TTB                             0x04C
+#define CAMMMU_LOCK                            0x050
+#define CAMMMU_LD_TLB                          0x054
+#define CAMMMU_CAM                             0x058
+#define CAMMMU_RAM                             0x05C
+#define CAMMMU_GFLUSH                          0x060
+#define CAMMMU_FLUSH_ENTRY                     0x064
+#define CAMMMU_READ_CAM                                0x068
+#define CAMMMU_READ_RAM                                0x06C
+#define CAMMMU_EMU_FAULT_AD                    0x070
+
+/* Define bit fields within selected registers */
+#define CAM_REVISION_MAJOR                     (15 << 4)
+#define CAM_REVISION_MAJOR_SHIFT               4
+#define CAM_REVISION_MINOR                     (15 << 0)
+#define CAM_REVISION_MINOR_SHIFT               0
+
+#define CAM_SYSCONFIG_SOFTRESET                        (1 <<  1)
+#define CAM_SYSCONFIG_AUTOIDLE                 (1 <<  0)
+
+#define CAM_SYSSTATUS_RESETDONE                        (1 <<  0)
+
+#define CAM_IRQSTATUS_CC_IRQ                   (1 <<  4)
+#define CAM_IRQSTATUS_MMU_IRQ                  (1 <<  3)
+#define CAM_IRQSTATUS_DMA_IRQ2                 (1 <<  2)
+#define CAM_IRQSTATUS_DMA_IRQ1                 (1 <<  1)
+#define CAM_IRQSTATUS_DMA_IRQ0                 (1 <<  0)
+
+#define CAM_GPO_CAM_S_P_EN                     (1 <<  1)
+#define CAM_GPO_CAM_CCP_MODE                   (1 <<  0)
+
+#define CAM_GPI_CC_DMA_REQ1                    (1 << 24)
+#define CAP_GPI_CC_DMA_REQ0                    (1 << 23)
+#define CAP_GPI_CAM_MSTANDBY                   (1 << 21)
+#define CAP_GPI_CAM_WAIT                       (1 << 20)
+#define CAP_GPI_CAM_S_DATA                     (1 << 17)
+#define CAP_GPI_CAM_S_CLK                      (1 << 16)
+#define CAP_GPI_CAM_P_DATA                     (0xFFF << 3)
+#define CAP_GPI_CAM_P_DATA_SHIFT               3
+#define CAP_GPI_CAM_P_VS                       (1 <<  2)
+#define CAP_GPI_CAM_P_HS                       (1 <<  1)
+#define CAP_GPI_CAM_P_CLK                      (1 <<  0)
+
+#define CC_REVISION_MAJOR                      (15 << 4)
+#define CC_REVISION_MAJOR_SHIFT                        4
+#define CC_REVISION_MINOR                      (15 << 0)
+#define CC_REVISION_MINOR_SHIFT                        0
+
+#define CC_SYSCONFIG_SIDLEMODE                 (3 <<  3)
+#define CC_SYSCONFIG_SIDLEMODE_FIDLE           (0 <<  3)
+#define CC_SYSCONFIG_SIDLEMODE_NIDLE           (1 <<  3)
+#define CC_SYSCONFIG_SOFTRESET                 (1 <<  1)
+#define CC_SYSCONFIG_AUTOIDLE                  (1 <<  0)
+
+#define CC_SYSSTATUS_RESETDONE                 (1 <<  0)
+
+#define CC_IRQSTATUS_FS_IRQ                    (1 << 19)
+#define CC_IRQSTATUS_LE_IRQ                    (1 << 18)
+#define CC_IRQSTATUS_LS_IRQ                    (1 << 17)
+#define CC_IRQSTATUS_FE_IRQ                    (1 << 16)
+#define CC_IRQSTATUS_FW_ERR_IRQ                        (1 << 10)
+#define CC_IRQSTATUS_FSC_ERR_IRQ               (1 <<  9)
+#define CC_IRQSTATUS_SSC_ERR_IRQ               (1 <<  8)
+#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ          (1 <<  4)
+#define CC_IRQSTATUS_FIFO_FULL_IRQ             (1 <<  3)
+#define CC_IRQSTATUS_FIFO_THR_IRQ              (1 <<  2)
+#define CC_IRQSTATUS_FIFO_OF_IRQ               (1 <<  1)
+#define CC_IRQSTATUS_FIFO_UF_IRQ               (1 <<  0)
+
+#define CC_IRQENABLE_FS_IRQ                    (1 << 19)
+#define CC_IRQENABLE_LE_IRQ                    (1 << 18)
+#define CC_IRQENABLE_LS_IRQ                    (1 << 17)
+#define CC_IRQENABLE_FE_IRQ                    (1 << 16)
+#define CC_IRQENABLE_FW_ERR_IRQ                        (1 << 10)
+#define CC_IRQENABLE_FSC_ERR_IRQ               (1 <<  9)
+#define CC_IRQENABLE_SSC_ERR_IRQ               (1 <<  8)
+#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ          (1 <<  4)
+#define CC_IRQENABLE_FIFO_FULL_IRQ             (1 <<  3)
+#define CC_IRQENABLE_FIFO_THR_IRQ              (1 <<  2)
+#define CC_IRQENABLE_FIFO_OF_IRQ               (1 <<  1)
+#define CC_IRQENABLE_FIFO_UF_IRQ               (1 <<  0)
+
+#define CC_CTRL_CC_ONE_SHOT                    (1 << 20)
+#define CC_CTRL_CC_IF_SYNCHRO                  (1 << 19)
+#define CC_CTRL_CC_RST                         (1 << 18)
+#define CC_CTRL_CC_FRAME_TRIG                  (1 << 17)
+#define CC_CTRL_CC_EN                          (1 << 16)
+#define CC_CTRL_NOBT_SYNCHRO                   (1 << 13)
+#define CC_CTRL_BT_CORRECT                     (1 << 12)
+#define CC_CTRL_PAR_ORDERCAM                   (1 << 11)
+#define CC_CTRL_PAR_CLK_POL                    (1 << 10)
+#define CC_CTRL_NOBT_HS_POL                    (1 <<  9)
+#define CC_CTRL_NOBT_VS_POL                    (1 <<  8)
+#define CC_CTRL_PAR_MODE                       (7 <<  1)
+#define CC_CTRL_PAR_MODE_SHIFT                 1
+#define CC_CTRL_PAR_MODE_NOBT8                 (0 <<  1)
+#define CC_CTRL_PAR_MODE_NOBT10                        (1 <<  1)
+#define CC_CTRL_PAR_MODE_NOBT12                        (2 <<  1)
+#define CC_CTRL_PAR_MODE_BT8                   (4 <<  1)
+#define CC_CTRL_PAR_MODE_BT10                  (5 <<  1)
+#define CC_CTRL_PAR_MODE_FIFOTEST              (7 <<  1)
+#define CC_CTRL_CCP_MODE                       (1 <<  0)
+
+#define CC_CTRL_DMA_EN                         (1 <<  8)
+#define CC_CTRL_DMA_FIFO_THRESHOLD             (0x7F << 0)
+#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT       0
+
+#define CC_CTRL_XCLK_DIV                       (0x1F << 0)
+#define CC_CTRL_XCLK_DIV_SHIFT                 0
+#define CC_CTRL_XCLK_DIV_STABLE_LOW            (0 <<  0)
+#define CC_CTRL_XCLK_DIV_STABLE_HIGH           (1 <<  0)
+#define CC_CTRL_XCLK_DIV_BYPASS                        (31 << 0)
+
+#define CC_TEST_FIFO_RD_POINTER                        (0xFF << 24)
+#define CC_TEST_FIFO_RD_POINTER_SHIFT          24
+#define CC_TEST_FIFO_WR_POINTER                        (0xFF << 16)
+#define CC_TEST_FIFO_WR_POINTER_SHIFT          16
+#define CC_TEST_FIFO_LEVEL                     (0xFF <<  8)
+#define CC_TEST_FIFO_LEVEL_SHIFT               8
+#define CC_TEST_FIFO_LEVEL_PEAK                        (0xFF <<  0)
+#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT          0
+
+#define CC_GENPAR_FIFO_DEPTH                   (7 <<  0)
+#define CC_GENPAR_FIFO_DEPTH_SHIFT             0
+
+#define CC_CCPDFR_ALPHA                                (0xFF <<  8)
+#define CC_CCPDFR_ALPHA_SHIFT                  8
+#define CC_CCPDFR_DATAFORMAT                   (15 <<  0)
+#define CC_CCPDFR_DATAFORMAT_SHIFT             0
+#define CC_CCPDFR_DATAFORMAT_YUV422BE          ( 0 <<  0)
+#define CC_CCPDFR_DATAFORMAT_YUV422            ( 1 <<  0)
+#define CC_CCPDFR_DATAFORMAT_YUV420            ( 2 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB444            ( 4 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB565            ( 5 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB888NDE         ( 6 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RGB888            ( 7 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW8NDE           ( 8 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW8              ( 9 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW10NDE          (10 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW10             (11 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW12NDE          (12 <<  0)
+#define CC_CCPDFR_DATAFORMAT_RAW12             (13 <<  0)
+#define CC_CCPDFR_DATAFORMAT_JPEG8             (15 <<  0)
+
+#define CAMDMA_REVISION_MAJOR                  (15 << 4)
+#define CAMDMA_REVISION_MAJOR_SHIFT            4
+#define CAMDMA_REVISION_MINOR                  (15 << 0)
+#define CAMDMA_REVISION_MINOR_SHIFT            0
+
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE         (3 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY        (0 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY        (1 << 12)
+#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY        (2 << 12)
+#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK                (1 <<  9)
+#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK         (1 <<  8)
+#define CAMDMA_OCP_SYSCONFIG_EMUFREE           (1 <<  5)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE         (3 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE   (0 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE   (1 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE   (2 <<  3)
+#define CAMDMA_OCP_SYSCONFIG_SOFTRESET         (1 <<  1)
+#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE          (1 <<  0)
+
+#define CAMDMA_SYSSTATUS_RESETDONE             (1 <<  0)
+
+#define CAMDMA_GCR_ARBITRATION_RATE            (0xFF << 16)
+#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT      16
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH      (0xFF << 0)
+#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT        0
+
+#define CAMDMA_CCR_SEL_SRC_DST_SYNC            (1 << 24)
+#define CAMDMA_CCR_PREFETCH                    (1 << 23)
+#define CAMDMA_CCR_SUPERVISOR                  (1 << 22)
+#define CAMDMA_CCR_SECURE                      (1 << 21)
+#define CAMDMA_CCR_BS                          (1 << 18)
+#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE     (1 << 17)
+#define CAMDMA_CCR_CONSTANT_FILL_ENABLE                (1 << 16)
+#define CAMDMA_CCR_DST_AMODE                   (3 << 14)
+#define CAMDMA_CCR_DST_AMODE_CONST_ADDR                (0 << 14)
+#define CAMDMA_CCR_DST_AMODE_POST_INC          (1 << 14)
+#define CAMDMA_CCR_DST_AMODE_SGL_IDX           (2 << 14)
+#define CAMDMA_CCR_DST_AMODE_DBL_IDX           (3 << 14)
+#define CAMDMA_CCR_SRC_AMODE                   (3 << 12)
+#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR                (0 << 12)
+#define CAMDMA_CCR_SRC_AMODE_POST_INC          (1 << 12)
+#define CAMDMA_CCR_SRC_AMODE_SGL_IDX           (2 << 12)
+#define CAMDMA_CCR_SRC_AMODE_DBL_IDX           (3 << 12)
+#define CAMDMA_CCR_WR_ACTIVE                   (1 << 10)
+#define CAMDMA_CCR_RD_ACTIVE                   (1 <<  9)
+#define CAMDMA_CCR_SUSPEND_SENSITIVE           (1 <<  8)
+#define CAMDMA_CCR_ENABLE                      (1 <<  7)
+#define CAMDMA_CCR_PRIO                                (1 <<  6)
+#define CAMDMA_CCR_FS                          (1 <<  5)
+#define CAMDMA_CCR_SYNCHRO                     ((3 << 19) | (31 << 0))
+#define CAMDMA_CCR_SYNCHRO_CAMERA              0x01
+
+#define CAMDMA_CLNK_CTRL_ENABLE_LNK            (1 << 15)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID            (0x1F << 0)
+#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT      0
+
+#define CAMDMA_CICR_MISALIGNED_ERR_IE          (1 << 11)
+#define CAMDMA_CICR_SUPERVISOR_ERR_IE          (1 << 10)
+#define CAMDMA_CICR_SECURE_ERR_IE              (1 <<  9)
+#define CAMDMA_CICR_TRANS_ERR_IE               (1 <<  8)
+#define CAMDMA_CICR_PACKET_IE                  (1 <<  7)
+#define CAMDMA_CICR_BLOCK_IE                   (1 <<  5)
+#define CAMDMA_CICR_LAST_IE                    (1 <<  4)
+#define CAMDMA_CICR_FRAME_IE                   (1 <<  3)
+#define CAMDMA_CICR_HALF_IE                    (1 <<  2)
+#define CAMDMA_CICR_DROP_IE                    (1 <<  1)
+
+#define CAMDMA_CSR_MISALIGNED_ERR              (1 << 11)
+#define CAMDMA_CSR_SUPERVISOR_ERR              (1 << 10)
+#define CAMDMA_CSR_SECURE_ERR                  (1 <<  9)
+#define CAMDMA_CSR_TRANS_ERR                   (1 <<  8)
+#define CAMDMA_CSR_PACKET                      (1 <<  7)
+#define CAMDMA_CSR_SYNC                                (1 <<  6)
+#define CAMDMA_CSR_BLOCK                       (1 <<  5)
+#define CAMDMA_CSR_LAST                                (1 <<  4)
+#define CAMDMA_CSR_FRAME                       (1 <<  3)
+#define CAMDMA_CSR_HALF                                (1 <<  2)
+#define CAMDMA_CSR_DROP                                (1 <<  1)
+
+#define CAMDMA_CSDP_SRC_ENDIANNESS             (1 << 21)
+#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK                (1 << 20)
+#define CAMDMA_CSDP_DST_ENDIANNESS             (1 << 19)
+#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK                (1 << 18)
+#define CAMDMA_CSDP_WRITE_MODE                 (3 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_WRNP            (0 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED          (1 << 16)
+#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP        (2 << 16)
+#define CAMDMA_CSDP_DST_BURST_EN               (3 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_1             (0 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_16            (1 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_32            (2 << 14)
+#define CAMDMA_CSDP_DST_BURST_EN_64            (3 << 14)
+#define CAMDMA_CSDP_DST_PACKED                 (1 << 13)
+#define CAMDMA_CSDP_WR_ADD_TRSLT               (15 << 9)
+#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD        (3 <<  9)
+#define CAMDMA_CSDP_SRC_BURST_EN               (3 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_1             (0 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_16            (1 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_32            (2 <<  7)
+#define CAMDMA_CSDP_SRC_BURST_EN_64            (3 <<  7)
+#define CAMDMA_CSDP_SRC_PACKED                 (1 <<  6)
+#define CAMDMA_CSDP_RD_ADD_TRSLT               (15 << 2)
+#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD        (3 <<  2)
+#define CAMDMA_CSDP_DATA_TYPE                  (3 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_8BITS            (0 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_16BITS           (1 <<  0)
+#define CAMDMA_CSDP_DATA_TYPE_32BITS           (2 <<  0)
+
+#define CAMMMU_SYSCONFIG_AUTOIDLE              (1 <<  0)
+
+/*
+ *
+ * Declarations.
+ *
+ */
+
+/* forward declarations */
+struct omap24xxcam_sgdma;
+struct omap24xxcam_dma;
+
+typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
+                                u32 status, void *arg);
+typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
+                              u32 status, void *arg);
+
+struct channel_state {
+       dma_callback_t callback;
+       void *arg;
+};
+
+/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
+struct sgdma_state {
+       const struct scatterlist *sglist;
+       int sglen;               /* number of sglist entries */
+       int next_sglist;         /* index of next sglist entry to process */
+       unsigned int bytes_read; /* number of bytes read */
+       unsigned int len;        /* total length of sglist (excluding
+                                 * bytes due to page alignment) */
+       int queued_sglist;       /* number of sglist entries queued for DMA */
+       u32 csr;                 /* DMA return code */
+       sgdma_callback_t callback;
+       void *arg;
+};
+
+/* physical DMA channel management */
+struct omap24xxcam_dma {
+       spinlock_t lock;        /* Lock for the whole structure. */
+
+       unsigned long base;     /* base address for dma controller */
+
+       /* While dma_stop!=0, an attempt to start a new DMA transfer will
+        * fail.
+        */
+       atomic_t dma_stop;
+       int free_dmach;         /* number of dma channels free */
+       int next_dmach;         /* index of next dma channel to use */
+       struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
+};
+
+/* scatter-gather DMA (scatterlist stuff) management */
+struct omap24xxcam_sgdma {
+       struct omap24xxcam_dma dma;
+
+       spinlock_t lock;        /* Lock for the fields below. */
+       int free_sgdma;         /* number of free sg dma slots */
+       int next_sgdma;         /* index of next sg dma slot to use */
+       struct sgdma_state sg_state[NUM_SG_DMA];
+
+       /* Reset timer data */
+       struct timer_list reset_timer;
+};
+
+/* per-device data structure */
+struct omap24xxcam_device {
+       /*** mutex  ***/
+       /*
+        * mutex serialises access to this structure. Also camera
+        * opening and releasing is synchronised by this.
+        */
+       struct mutex mutex;
+
+       /*** general driver state information ***/
+       atomic_t users;
+       /*
+        * Lock to serialise core enabling and disabling and access to
+        * sgdma_in_queue.
+        */
+       spinlock_t core_enable_disable_lock;
+       /*
+        * Number or sgdma requests in scatter-gather queue, protected
+        * by the lock above.
+        */
+       int sgdma_in_queue;
+       /*
+        * Sensor interface parameters: interface type, CC_CTRL
+        * register value and interface specific data.
+        */
+       int if_type;
+       union {
+               struct parallel {
+                       u32 xclk;
+               } bt656;
+       } if_u;
+       u32 cc_ctrl;
+
+       /*** subsystem structures ***/
+       struct omap24xxcam_sgdma sgdma;
+
+       /*** hardware resources ***/
+       unsigned int irq;
+       unsigned long mmio_base;
+       unsigned long mmio_base_phys;
+       unsigned long mmio_size;
+
+       /*** interfaces and device ***/
+       struct v4l2_int_device *sdev;
+       struct device *dev;
+       struct video_device *vfd;
+
+       /*** camera and sensor reset related stuff ***/
+       struct work_struct sensor_reset_work;
+       /*
+        * We're in the middle of a reset. Don't enable core if this
+        * is non-zero! This exists to help decisionmaking in a case
+        * where videobuf_qbuf is called while we are in the middle of
+        * a reset.
+        */
+       atomic_t in_reset;
+       /*
+        * Non-zero if we don't want any resets for now. Used to
+        * prevent reset work to run when we're about to stop
+        * streaming.
+        */
+       atomic_t reset_disable;
+
+       /*** video device parameters ***/
+       int capture_mem;
+
+       /*** camera module clocks ***/
+       struct clk *fck;
+       struct clk *ick;
+
+       /*** capture data ***/
+       /* file handle, if streaming is on */
+       struct file *streaming;
+};
+
+/* Per-file handle data. */
+struct omap24xxcam_fh {
+       spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+       struct videobuf_queue vbq;
+       struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
+       atomic_t field_count; /* field counter for videobuf_buffer */
+       /* accessing cam here doesn't need serialisation: it's constant */
+       struct omap24xxcam_device *cam;
+};
+
+/*
+ *
+ * Register I/O functions.
+ *
+ */
+
+static __inline__ u32 omap24xxcam_reg_in(unsigned long base, u32 offset)
+{
+       return readl(base + offset);
+}
+
+static __inline__ u32 omap24xxcam_reg_out(unsigned long base, u32 offset,
+                                         u32 val)
+{
+       writel(val, base + offset);
+       return val;
+}
+
+static __inline__ u32 omap24xxcam_reg_merge(unsigned long base, u32 offset,
+                                           u32 val, u32 mask)
+{
+       u32 addr = base + offset;
+       u32 new_val = (readl(addr) & ~mask) | (val & mask);
+
+       writel(new_val, addr);
+       return new_val;
+}
+
+/*
+ *
+ * Function prototypes.
+ *
+ */
+
+/* dma prototypes */
+
+void omap24xxcam_dma_hwinit(const struct omap24xxcam_dma *dma);
+void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
+
+/* sgdma prototypes */
+
+void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
+int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
+                           const struct scatterlist *sglist, int sglen,
+                           int len, sgdma_callback_t callback, void *arg);
+void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
+void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
+                           unsigned long base,
+                           void (*reset_callback)(unsigned long data),
+                           unsigned long reset_callback_data);
+void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
+
+#endif
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
new file mode 100644 (file)
index 0000000..a0f7406
--- /dev/null
@@ -0,0 +1,1279 @@
+/*
+ * drivers/media/video/ov9640.c
+ *
+ * OV9640 sensor driver
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ * Contact: Trilok Soni <soni.trilok@gmail.com>
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-int-device.h>
+
+#include "ov9640.h"
+
+#define DRIVER_NAME  "ov9640"
+
+struct ov9640_sensor {
+       const struct ov9640_platform_data *pdata;
+       struct v4l2_int_device *v4l2_int_device;
+       struct i2c_client *i2c_client;
+       struct v4l2_pix_format pix;
+       struct v4l2_fract timeperframe;
+       int ver;                                /*ov9640 chip version*/
+};
+
+static struct ov9640_sensor ov9640;
+static struct i2c_driver ov9640sensor_i2c_driver;
+
+/* list of image formats supported by OV9640 sensor */
+const static struct v4l2_fmtdesc ov9640_formats[] = {
+       {
+               /* Note:  V4L2 defines RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+                *
+                * We interpret RGB565 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+                */
+               .description    = "RGB565, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB565,
+       },
+       {
+               /* Note:  V4L2 defines RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      b4 b3 b2 b1 b0 g5 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB565X as:
+                *
+                *      Byte 0                    Byte 1
+                *      r4 r3 r2 r1 r0 g5 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB565, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB565X,
+       },
+       {
+               .description    = "YUYV (YUV 4:2:2), packed",
+               .pixelformat    = V4L2_PIX_FMT_YUYV,
+       },
+       {
+               .description    = "UYVY, packed",
+               .pixelformat    = V4L2_PIX_FMT_UYVY,
+       },
+       {
+               /* Note:  V4L2 defines RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 r4 r3 r2 r1 r0   x  b4 b3 b2 b1 b0 g4 g3
+                *
+                * We interpret RGB555 as:
+                *
+                *      Byte 0                    Byte 1
+                *      g2 g1 g0 b4 b3 b2 b1 b0   x  r4 r3 r2 r1 r0 g4 g3
+                */
+               .description    = "RGB555, le",
+               .pixelformat    = V4L2_PIX_FMT_RGB555,
+       },
+       {
+               /* Note:  V4L2 defines RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  b4 b3 b2 b1 b0 g4 g3   g2 g1 g0 r4 r3 r2 r1 r0
+                *
+                * We interpret RGB555X as:
+                *
+                *      Byte 0                    Byte 1
+                *      x  r4 r3 r2 r1 r0 g4 g3   g2 g1 g0 b4 b3 b2 b1 b0
+                */
+               .description    = "RGB555, be",
+               .pixelformat    = V4L2_PIX_FMT_RGB555X,
+       },
+};
+
+#define NUM_CAPTURE_FORMATS ARRAY_SIZE(ov9640_formats)
+
+/*
+ * OV9640 register configuration for all combinations of pixel format and
+ * image size
+ */
+       /* YUV (YCbCr) QQCIF */
+const static struct ov9640_reg qqcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QQVGA */
+const static struct ov9640_reg qqvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QCIF */
+const static struct ov9640_reg qcif_yuv[] = {
+       { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) QVGA */
+const static struct ov9640_reg qvga_yuv[] = {
+       { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) CIF */
+const static struct ov9640_reg cif_yuv[] = {
+       { 0x12, 0x20 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) VGA */
+const static struct ov9640_reg vga_yuv[] = {
+       { 0x12, 0x40 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* YUV (YCbCr) SXGA */
+const static struct ov9640_reg sxga_yuv[] = {
+       { 0x12, 0x00 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x0F },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQCIF */
+const static struct ov9640_reg qqcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QQVGA */
+const static struct ov9640_reg qqvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QCIF */
+const static struct ov9640_reg qcif_565[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 QVGA */
+const static struct ov9640_reg qvga_565[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 CIF */
+const static struct ov9640_reg cif_565[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 VGA */
+const static struct ov9640_reg vga_565[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB565 SXGA */
+const static struct ov9640_reg sxga_565[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQCIF */
+const static struct ov9640_reg qqcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QQVGA */
+const static struct ov9640_reg qqvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QCIF */
+const static struct ov9640_reg qcif_555[] = {
+       { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 QVGA */
+const static struct ov9640_reg qvga_555[] = {
+       { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 CIF */
+const static struct ov9640_reg cif_555[] = {
+       { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 VGA */
+const static struct ov9640_reg vga_555[] = {
+       { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+       /* RGB555 SXGA */
+const static struct ov9640_reg sxga_555[] = {
+       { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */
+       { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */
+       { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */
+       { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */
+       { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */
+       { 0x58, 0x65 },                                 /* MTXS */
+       { OV9640_REG_TERM, OV9640_VAL_TERM }
+};
+
+
+#define DEF_GAIN         31
+#define DEF_AUTOGAIN      1
+#define DEF_EXPOSURE    154
+#define DEF_AEC           1
+#define DEF_FREEZE_AGCAEC 0
+#define DEF_BLUE        153
+#define DEF_RED         (255 - DEF_BLUE)
+#define DEF_AWB           1
+#define DEF_HFLIP         0
+#define DEF_VFLIP         0
+
+/* Our own specific controls */
+#define V4L2_CID_FREEZE_AGCAEC         V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_AUTOEXPOSURE          V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_LAST_PRIV             V4L2_CID_AUTOEXPOSURE
+
+/*  Video controls  */
+static struct vcontrol {
+       struct v4l2_queryctrl qc;
+       int current_value;
+       u8 reg;
+       u8 mask;
+       u8 start_bit;
+} video_control[] = {
+       {
+               {
+                       .id = V4L2_CID_GAIN,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Gain",
+                       .minimum = 0,
+                       .maximum = 63,
+                       .step = 1,
+                       .default_value = DEF_GAIN,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_GAIN,
+               .mask           = 0x3f,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_AUTOGAIN,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Auto Gain",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_AUTOGAIN,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_COM8,
+               .mask           = 0x04,
+               .start_bit      = 2,
+       },
+       {
+               {
+                       .id = V4L2_CID_EXPOSURE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Exposure",
+                       .minimum = 0,
+                       .maximum = 255,
+                       .step = 1,
+                       .default_value = DEF_EXPOSURE,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_AECH,
+               .mask           = 0xff,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_AUTOEXPOSURE,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Auto Exposure",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_AEC,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_COM8,
+               .mask           = 0x01,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_FREEZE_AGCAEC,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Freeze AGC/AEC",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_FREEZE_AGCAEC,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_COM9,
+               .mask           = 0x01,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_RED_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Red Balance",
+                       .minimum = 0,
+                       .maximum = 255,
+                       .step = 1,
+                       .default_value = DEF_RED,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_RED,
+               .mask           = 0xff,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_BLUE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "Blue Balance",
+                       .minimum = 0,
+                       .maximum = 255,
+                       .step = 1,
+                       .default_value = DEF_BLUE,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_BLUE,
+               .mask           = 0xff,
+               .start_bit      = 0,
+       },
+       {
+               {
+                       .id = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Auto White Balance",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_AWB,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_COM8,
+               .mask           = 0x02,
+               .start_bit      = 1,
+       },
+       {
+               {
+                       .id = V4L2_CID_HFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Mirror Image",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_HFLIP,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_MVFP,
+               .mask           = 0x20,
+               .start_bit      = 5,
+       },
+       {
+               {
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "Vertical Flip",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 0,
+                       .default_value = DEF_VFLIP,
+               },
+               .current_value  = 0,
+               .reg            = OV9640_MVFP,
+               .mask           = 0x10,
+               .start_bit      = 4,
+       },
+};
+
+const static struct ov9640_reg *
+       ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] =
+{
+ { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv },
+ { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 },
+ { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 },
+};
+
+
+/*
+ * Read a value from a register in an OV9640 sensor device.
+ * The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[1];
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       *data = reg;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0) {
+               msg->flags = I2C_M_RD;
+               err = i2c_transfer(client->adapter, msg, 1);
+       }
+       if (err >= 0) {
+               *val = *data;
+               return 0;
+       }
+       return err;
+}
+
+/*
+ * Write a value to a register in an OV9640 sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+       int err;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 2;
+       msg->buf = data;
+       data[0] = reg;
+       data[1] = val;
+       err = i2c_transfer(client->adapter, msg, 1);
+       if (err >= 0)
+               return 0;
+       return err;
+}
+
+static int
+ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       u8 oldval, newval;
+       int rc;
+
+       if (mask == 0xff)
+               newval = *val;
+       else {
+               /* need to do read - modify - write */
+               rc = ov9640_read_reg(client, reg, &oldval);
+               if (rc)
+                       return rc;
+               oldval &= (~mask);              /* Clear the masked bits */
+               *val &= mask;                  /* Enforce mask on value */
+               newval = oldval | *val;        /* Set the desired bits */
+       }
+
+       /* write the new value to the register */
+       rc = ov9640_write_reg(client, reg, newval);
+       if (rc)
+               return rc;
+
+       rc = ov9640_read_reg(client, reg, &newval);
+       if (rc)
+               return rc;
+
+       *val = newval & mask;
+       return 0;
+}
+
+static int
+ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask)
+{
+       int rc;
+
+       rc = ov9640_read_reg(client, reg, val);
+       if (rc)
+               return rc;
+       (*val) &= mask;
+
+       return 0;
+}
+
+/*
+ * Initialize a list of OV9640 registers.
+ * The list of registers is terminated by the pair of values
+ * { OV9640_REG_TERM, OV9640_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[])
+{
+       int err;
+       const struct ov9640_reg *next = reglist;
+
+       while (!((next->reg == OV9640_REG_TERM)
+               && (next->val == OV9640_VAL_TERM))) {
+               err = ov9640_write_reg(client, next->reg, next->val);
+               udelay(100);
+               if (err)
+                       return err;
+               next++;
+       }
+       return 0;
+}
+
+/* Returns the index of the requested ID from the control structure array */
+static int
+find_vctrl(int id)
+{
+       int i;
+
+       if (id < V4L2_CID_BASE)
+               return -EDOM;
+
+       for (i = (ARRAY_SIZE(video_control) - 1); i >= 0; i--)
+               if (video_control[i].qc.id == id)
+                       break;
+       if (i < 0)
+               i = -EINVAL;
+       return i;
+}
+
+/*
+ * Calculate the internal clock divisor (value of the CLKRC register) of the
+ * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a
+ * desired frame period (in seconds).  The frame period 'fper' is expressed as
+ * a fraction.  The frame period is an input/output parameter.
+ * Returns the value of the OV9640 CLKRC register that will yield the frame
+ * period returned in 'fper' at the specified xclk frequency.  The
+ * returned period will be as close to the requested period as possible.
+ */
+static unsigned char
+ov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper)
+{
+       unsigned long fpm, fpm_max;     /* frames per minute */
+       unsigned long divisor;
+       const unsigned long divisor_max = 64;
+       /* FIXME
+        * clks_per_frame should come from platform data
+        */
+#ifdef CONFIG_ARCH_OMAP24XX
+       const static unsigned long clks_per_frame[] =
+               { 200000, 400000, 200000, 400000, 400000, 800000, 3200000 };
+      /*         QQCIF   QQVGA    QCIF    QVGA  CIF     VGA    SXGA
+       *         199680,400000, 199680, 400000, 399360, 800000, 3200000
+       */
+#else
+       const static unsigned long clks_per_frame[] =
+               { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 };
+#endif
+
+       if (fper->numerator > 0)
+               fpm = (fper->denominator*60)/fper->numerator;
+       else
+               fpm = 0xffffffff;
+       fpm_max = (xclk*60)/clks_per_frame[isize];
+       if (fpm_max == 0)
+               fpm_max = 1;
+       if (fpm > fpm_max)
+               fpm = fpm_max;
+       if (fpm == 0)
+               fpm = 1;
+       divisor = fpm_max/fpm;
+       if (divisor > divisor_max)
+               divisor = divisor_max;
+       fper->numerator = divisor*60;
+       fper->denominator = fpm_max;
+
+       /* try to reduce the fraction */
+       while (!(fper->denominator % 5) && !(fper->numerator % 5)) {
+               fper->numerator /= 5;
+               fper->denominator /= 5;
+       }
+       while (!(fper->denominator % 3) && !(fper->numerator % 3)) {
+               fper->numerator /= 3;
+               fper->denominator /= 3;
+       }
+       while (!(fper->denominator % 2) && !(fper->numerator % 2)) {
+               fper->numerator /= 2;
+               fper->denominator /= 2;
+       }
+       if (fper->numerator < fper->denominator) {
+               if (!(fper->denominator % fper->numerator)) {
+                       fper->denominator /= fper->numerator;
+                       fper->numerator = 1;
+               }
+       } else {
+               if (!(fper->numerator % fper->denominator)) {
+                       fper->numerator /= fper->denominator;
+                       fper->denominator = 1;
+               }
+       }
+
+       /* we set bit 7 in CLKRC to enable the digital PLL */
+       return (0x80 | (divisor - 1));
+}
+
+/*
+ * Find the best match for a requested image capture size.  The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size
+ov9640_find_size(unsigned int width, unsigned int height)
+{
+       enum image_size isize;
+       unsigned long pixels = width*height;
+
+       for (isize = QQCIF; isize < SXGA; isize++) {
+               if (ov9640_sizes[isize + 1].height *
+                       ov9640_sizes[isize + 1].width > pixels)
+                       return isize;
+       }
+       return SXGA;
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency
+ */
+static unsigned long
+ov9640sensor_calc_xclk(struct i2c_client *c)
+{
+       struct ov9640_sensor *sensor = i2c_get_clientdata(c);
+       struct v4l2_fract *timeperframe = &sensor->timeperframe;
+       struct v4l2_pix_format *pix = &sensor->pix;
+
+       unsigned long tgt_xclk;                 /* target xclk */
+       unsigned long tgt_fpm;                  /* target frames per minute */
+       enum image_size isize;
+
+       /*
+        * We use arbitrary rules to select the xclk frequency.  If the
+        * capture size is VGA and the frame rate is greater than 900
+        * frames per minute, or if the capture size is SXGA and the
+        * frame rate is greater than 450 frames per minutes, then the
+        * xclk frequency will be set to 48MHz.  Otherwise, the xclk
+        * frequency will be set to 24MHz.  If the mclk frequency is such that
+        * the target xclk frequency is not achievable, then xclk will be set
+        * as close as to the target as possible.
+        */
+       tgt_fpm = (timeperframe->denominator*60)
+               / timeperframe->numerator;
+       tgt_xclk = OV9640_XCLK_NOM;
+       isize = ov9640_find_size(pix->width, pix->height);
+       switch (isize) {
+       case SXGA:
+               if (tgt_fpm > 450)
+                       tgt_xclk = OV9640_XCLK_MAX;
+               break;
+       case VGA:
+               if (tgt_fpm > 900)
+                       tgt_xclk = OV9640_XCLK_MAX;
+               break;
+       default:
+               break;
+       }
+       return tgt_xclk;
+}
+
+/*
+ * Configure the OV9640 for a specified image size, pixel format, and frame
+ * period.  xclk is the frequency (in Hz) of the xclk input to the OV9640.
+ * fper is the frame period (in seconds) expressed as a fraction.
+ * Returns zero if successful, or non-zero otherwise.
+ * The actual frame period is returned in fper.
+ */
+static int ov9640_configure(struct v4l2_int_device *s)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct v4l2_pix_format *pix = &sensor->pix;
+       struct v4l2_fract *fper = &sensor->timeperframe;
+       struct i2c_client *client = sensor->i2c_client;
+       enum image_size isize;
+       unsigned long xclk;
+
+       int err;
+       unsigned char clkrc;
+       enum pixel_format pfmt = YUV;
+
+       switch (pix->pixelformat) {
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+               pfmt = RGB565;
+               break;
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_RGB555X:
+               pfmt = RGB555;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       default:
+               pfmt = YUV;
+       }
+
+       xclk = ov9640sensor_calc_xclk(client);
+
+       isize = ov9640_find_size(pix->width, pix->height);
+
+       /* common register initialization */
+       err = ov9640_write_regs(client, sensor->pdata->default_regs);
+       if (err)
+               return err;
+
+       /* configure image size and pixel format */
+       err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]);
+       if (err)
+               return err;
+
+       /* configure frame rate */
+       clkrc = ov9640_clkrc(isize, xclk, fper);
+       err = ov9640_write_reg(client, OV9640_CLKRC, clkrc);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+/*
+ * Detect if an OV9640 is present, and if so which revision.
+ * A device is considered to be detected if the manufacturer ID (MIDH and MIDL)
+ * and the product ID (PID) registers match the expected values.
+ * Any value of the version ID (VER) register is accepted.
+ * Here are the version numbers we know about:
+ *     0x48 --> OV9640 Revision 1 or OV9640 Revision 2
+ *     0x49 --> OV9640 Revision 3
+ * Returns a negative error number if no device is detected, or the
+ * non-negative value of the version ID register if a device is detected.
+ */
+static int
+ov9640_detect(struct i2c_client *client)
+{
+       u8 midh, midl, pid, ver;
+
+       if (!client)
+               return -ENODEV;
+
+       if (ov9640_read_reg(client, OV9640_MIDH, &midh))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_MIDL, &midl))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_PID, &pid))
+               return -ENODEV;
+       if (ov9640_read_reg(client, OV9640_VER, &ver))
+               return -ENODEV;
+
+       if ((midh != OV9640_MIDH_MAGIC)
+               || (midl != OV9640_MIDL_MAGIC)
+               || (pid != OV9640_PID_MAGIC))
+               /*
+                * We didn't read the values we expected, so
+                * this must not be an OV9640.
+                */
+               return -ENODEV;
+
+       return ver;
+}
+
+/*
+ * following are sensor interface functions implemented by
+ * OV9640 sensor driver.
+ */
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+                               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       i = find_vctrl(qc->id);
+       if (i == -EINVAL) {
+               qc->flags = V4L2_CTRL_FLAG_DISABLED;
+               return 0;
+       }
+       if (i < 0)
+               return -EINVAL;
+
+       *qc = video_control[i].qc;
+       return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+                            struct v4l2_control *vc)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct i2c_client *client = sensor->i2c_client;
+       int i, val;
+       struct vcontrol *lvc;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &video_control[i];
+       if (ov9640_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask))
+               return -EIO;
+
+       val = val >> lvc->start_bit;
+       if (val >= 0) {
+               vc->value = lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+                            struct v4l2_control *vc)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct i2c_client *client = sensor->i2c_client;
+       struct vcontrol *lvc;
+       int val = vc->value;
+       int i;
+
+       i = find_vctrl(vc->id);
+       if (i < 0)
+               return -EINVAL;
+
+       lvc = &video_control[i];
+       val = val << lvc->start_bit;
+       if (ov9640_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask))
+               return -EIO;
+
+       val = val >> lvc->start_bit;
+       if (val >= 0) {
+               lvc->current_value = val;
+               return 0;
+       } else
+               return val;
+}
+
+/*
+ * Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type.
+ */
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+                                  struct v4l2_fmtdesc *fmt)
+{
+       int index = fmt->index;
+       enum v4l2_buf_type type = fmt->type;
+
+       memset(fmt, 0, sizeof(*fmt));
+       fmt->index = index;
+       fmt->type = type;
+
+       switch (fmt->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               if (index >= NUM_CAPTURE_FORMATS)
+                       return -EINVAL;
+       break;
+       default:
+               return -EINVAL;
+       }
+
+       fmt->flags = ov9640_formats[index].flags;
+       strlcpy(fmt->description, ov9640_formats[index].description,
+                                       sizeof(fmt->description));
+       fmt->pixelformat = ov9640_formats[index].pixelformat;
+
+       return 0;
+}
+
+/*
+ * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type.  This
+ * ioctl is used to negotiate the image capture size and pixel format
+ * without actually making it take effect.
+ */
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+                            struct v4l2_format *f)
+{
+       enum image_size isize;
+       int ifmt;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+
+       isize = ov9640_find_size(pix->width, pix->height);
+       pix->width = ov9640_sizes[isize].width;
+       pix->height = ov9640_sizes[isize].height;
+       for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) {
+               if (pix->pixelformat == ov9640_formats[ifmt].pixelformat)
+                       break;
+       }
+       if (ifmt == NUM_CAPTURE_FORMATS)
+               ifmt = 0;
+       pix->pixelformat = ov9640_formats[ifmt].pixelformat;
+       pix->field = V4L2_FIELD_NONE;
+       pix->bytesperline = pix->width*2;
+       pix->sizeimage = pix->bytesperline*pix->height;
+       pix->priv = 0;
+       switch (pix->pixelformat) {
+       case V4L2_PIX_FMT_YUYV:
+       case V4L2_PIX_FMT_UYVY:
+       default:
+               pix->colorspace = V4L2_COLORSPACE_JPEG;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_RGB555:
+       case V4L2_PIX_FMT_RGB555X:
+               pix->colorspace = V4L2_COLORSPACE_SRGB;
+               break;
+       }
+       return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+                               struct v4l2_format *f)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct v4l2_pix_format *pix = &f->fmt.pix;
+       int rval;
+
+       rval = ioctl_try_fmt_cap(s, f);
+       if (rval)
+               return rval;
+
+       rval = ov9640_configure(s);
+
+       if (!rval)
+               sensor->pix = *pix;
+
+       return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+                               struct v4l2_format *f)
+{
+       struct ov9640_sensor *sensor = s->priv;
+
+       f->fmt.pix = sensor->pix;
+
+       return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+                            struct v4l2_streamparm *a)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct v4l2_captureparm *cparm = &a->parm.capture;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(a, 0, sizeof(*a));
+       a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       cparm->capability = V4L2_CAP_TIMEPERFRAME;
+       cparm->timeperframe = sensor->timeperframe;
+
+       return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+                            struct v4l2_streamparm *a)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+       struct v4l2_fract timeperframe_old;
+       int rval;
+
+       timeperframe_old = sensor->timeperframe;
+       sensor->timeperframe = *timeperframe;
+
+       rval = ov9640_configure(s);
+
+       if (rval)
+               sensor->timeperframe = timeperframe_old;
+       else
+               *timeperframe = sensor->timeperframe;
+
+       return rval;
+}
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct i2c_client *client = sensor->i2c_client;
+       u32 xclk;       /* target xclk */
+       int rval;
+
+       rval = sensor->pdata->ifparm(p);
+       if (rval)
+               return rval;
+
+       xclk = ov9640sensor_calc_xclk(client);
+
+       p->u.bt656.clock_curr = xclk;
+
+       return 0;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+       struct ov9640_sensor *sensor = s->priv;
+
+       return sensor->pdata->power_set(on);
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+       return ov9640_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+       return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+       struct ov9640_sensor *sensor = s->priv;
+       struct i2c_client *c = sensor->i2c_client;
+       int err;
+
+       err = ov9640_detect(c);
+       if (err < 0) {
+               dev_err(&c->dev, "Unable to detect " DRIVER_NAME " sensor\n");
+               return err;
+       }
+
+       sensor->ver = err;
+       pr_info(DRIVER_NAME " chip version 0x%02x detected\n", sensor->ver);
+
+       return 0;
+}
+
+static struct v4l2_int_ioctl_desc ov9640_ioctl_desc[] = {
+       { vidioc_int_dev_init_num,
+         (v4l2_int_ioctl_func *)ioctl_dev_init },
+       { vidioc_int_dev_exit_num,
+         (v4l2_int_ioctl_func *)ioctl_dev_exit },
+       { vidioc_int_s_power_num,
+         (v4l2_int_ioctl_func *)ioctl_s_power },
+       { vidioc_int_g_ifparm_num,
+         (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+       { vidioc_int_init_num,
+         (v4l2_int_ioctl_func *)ioctl_init },
+       { vidioc_int_enum_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+       { vidioc_int_try_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+       { vidioc_int_g_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+       { vidioc_int_s_fmt_cap_num,
+         (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+       { vidioc_int_g_parm_num,
+         (v4l2_int_ioctl_func *)ioctl_g_parm },
+       { vidioc_int_s_parm_num,
+         (v4l2_int_ioctl_func *)ioctl_s_parm },
+       { vidioc_int_queryctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_queryctrl },
+       { vidioc_int_g_ctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+       { vidioc_int_s_ctrl_num,
+         (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave ov9640_slave = {
+       .ioctls         = ov9640_ioctl_desc,
+       .num_ioctls     = ARRAY_SIZE(ov9640_ioctl_desc),
+};
+
+static struct v4l2_int_device ov9640_int_device = {
+       .module = THIS_MODULE,
+       .name   = DRIVER_NAME,
+       .priv   = &ov9640,
+       .type   = v4l2_int_type_slave,
+       .u      = {
+               .slave = &ov9640_slave,
+       },
+};
+
+static int __init
+ov9640_probe(struct i2c_client *client)
+{
+       struct ov9640_sensor *sensor = &ov9640;
+       int err;
+
+       if (i2c_get_clientdata(client))
+               return -EBUSY;
+
+       sensor->pdata = client->dev.platform_data;
+
+       if (!sensor->pdata || !sensor->pdata->default_regs) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       sensor->v4l2_int_device = &ov9640_int_device;
+       sensor->i2c_client = client;
+
+       i2c_set_clientdata(client, sensor);
+
+       /* Make the default capture format QCIF RGB565 */
+       sensor->pix.width = ov9640_sizes[QCIF].width;
+       sensor->pix.height = ov9640_sizes[QCIF].height;
+       sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+       err = v4l2_int_device_register(sensor->v4l2_int_device);
+       if (err)
+               i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static int __exit
+ov9640_remove(struct i2c_client *client)
+{
+       struct ov9640_sensor *sensor = i2c_get_clientdata(client);
+
+       if (!client->adapter)
+               return -ENODEV; /* our client isn't attached */
+
+       v4l2_int_device_unregister(sensor->v4l2_int_device);
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+static struct i2c_driver ov9640sensor_i2c_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+       },
+       .probe  = ov9640_probe,
+       .remove = __exit_p(ov9640_remove),
+};
+
+static struct ov9640_sensor ov9640 = {
+       .timeperframe = {
+               .numerator = 1,
+               .denominator = 15,
+       },
+};
+
+static int ov9640sensor_init(void)
+{
+       int err;
+
+       err = i2c_add_driver(&ov9640sensor_i2c_driver);
+       if (err) {
+               printk(KERN_ERR "Failed to register" DRIVER_NAME ".\n");
+               return err;
+       }
+       return 0;
+}
+module_init(ov9640sensor_init);
+
+static void __exit ov9640sensor_cleanup(void)
+{
+       i2c_del_driver(&ov9640sensor_i2c_driver);
+}
+module_exit(ov9640sensor_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OV9640 camera sensor driver");
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h
new file mode 100644 (file)
index 0000000..a13fba9
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * drivers/media/video/ov9640.h
+ *
+ * Register definitions for the OmniVision OV9640 CameraChip.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OV9640_H
+#define OV9640_H
+
+#define OV9640_I2C_ADDR                0x30
+
+/* define register offsets for the OV9640 sensor chip */
+#define OV9640_GAIN            0x00
+#define OV9640_BLUE            0x01
+#define OV9640_RED             0x02
+#define OV9640_VREF            0x03
+#define OV9640_COM1            0x04
+#define OV9640_BAVE            0x05
+#define OV9640_GEAVE           0x06
+#define OV9640_RAVE            0x08
+#define OV9640_COM2            0x09
+#define OV9640_PID             0x0A
+#define OV9640_VER             0x0B
+#define OV9640_COM3            0x0C
+#define OV9640_COM4            0x0D
+#define OV9640_COM5            0x0E
+#define OV9640_COM6            0x0F
+#define OV9640_AECH            0x10
+#define OV9640_CLKRC           0x11
+#define OV9640_COM7            0x12
+#define OV9640_COM8            0x13
+#define OV9640_COM9            0x14
+#define OV9640_COM10           0x15
+#define OV9640_HSTRT           0x17
+#define OV9640_HSTOP           0x18
+#define OV9640_VSTRT           0x19
+#define OV9640_VSTOP           0x1A
+#define OV9640_PSHFT           0x1B
+#define OV9640_MIDH            0x1C
+#define OV9640_MIDL            0x1D
+#define OV9640_MVFP            0x1E
+#define OV9640_LAEC            0x1F
+#define OV9640_BOS             0x20
+#define OV9640_GBOS            0x21
+#define OV9640_GROS            0x22
+#define OV9640_ROS             0x23
+#define OV9640_AEW             0x24
+#define OV9640_AEB             0x25
+#define OV9640_VPT             0x26
+#define OV9640_BBIAS           0x27
+#define OV9640_GBBIAS          0x28
+#define OV9640_EXHCH           0x2A
+#define OV9640_EXHCL           0x2B
+#define OV9640_RBIAS           0x2C
+#define OV9640_ADVFL           0x2D
+#define OV9640_ADVFH           0x2E
+#define OV9640_YAVE            0x2F
+#define OV9640_HSYST           0x30
+#define OV9640_HSYEN           0x31
+#define OV9640_HREF            0x32
+#define OV9640_CHLF            0x33
+#define OV9640_ARBLM           0x34
+#define OV9640_ADC             0x37
+#define OV9640_ACOM            0x38
+#define OV9640_OFON            0x39
+#define OV9640_TSLB            0x3A
+#define OV9640_COM11           0x3B
+#define OV9640_COM12           0x3C
+#define OV9640_COM13           0x3D
+#define OV9640_COM14           0x3E
+#define OV9640_EDGE            0x3F
+#define OV9640_COM15           0x40
+#define OV9640_COM16           0x41
+#define OV9640_COM17           0x42
+#define OV9640_MTX1            0x4F
+#define OV9640_MTX2            0x50
+#define OV9640_MTX3            0x51
+#define OV9640_MTX4            0x52
+#define OV9640_MTX5            0x53
+#define OV9640_MTX6            0x54
+#define OV9640_MTX7            0x55
+#define OV9640_MTX8            0x56
+#define OV9640_MTX9            0x57
+#define OV9640_MTXS            0x58
+#define OV9640_LCC1            0x62
+#define OV9640_LCC2            0x63
+#define OV9640_LCC3            0x64
+#define OV9640_LCC4            0x65
+#define OV9640_LCC5            0x66
+#define OV9640_MANU            0x67
+#define OV9640_MANV            0x68
+#define OV9640_HV              0x69
+#define OV9640_MBD             0x6A
+#define OV9640_DBLV            0x6B
+#define OV9640_GSP1            0x6C
+#define OV9640_GSP2            0x6D
+#define OV9640_GSP3            0x6E
+#define OV9640_GSP4            0x6F
+#define OV9640_GSP5            0x70
+#define OV9640_GSP6            0x71
+#define OV9640_GSP7            0x72
+#define OV9640_GSP8            0x73
+#define OV9640_GSP9            0x74
+#define OV9640_GSP10           0x75
+#define OV9640_GSP11           0x76
+#define OV9640_GSP12           0x77
+#define OV9640_GSP13           0x78
+#define OV9640_GSP14           0x79
+#define OV9640_GSP15           0x7A
+#define OV9640_GSP16           0x7B
+#define OV9640_GST1            0x7C
+#define OV9640_GST2            0x7D
+#define OV9640_GST3            0x7E
+#define OV9640_GST4            0x7F
+#define OV9640_GST5            0x80
+#define OV9640_GST6            0x81
+#define OV9640_GST7            0x82
+#define OV9640_GST8            0x83
+#define OV9640_GST9            0x84
+#define OV9640_GST10           0x85
+#define OV9640_GST11           0x86
+#define OV9640_GST12           0x87
+#define OV9640_GST13           0x88
+#define OV9640_GST14           0x89
+#define OV9640_GST15           0x8A
+
+#define OV9640_NUM_REGS                (OV9640_GST15 + 1)
+
+#define OV9640_PID_MAGIC       0x96    /* high byte of product ID number */
+#define OV9640_VER_REV2                0x48    /* low byte of product ID number */
+#define OV9640_VER_REV3                0x49    /* low byte of product ID number */
+#define OV9640_MIDH_MAGIC      0x7F    /* high byte of mfg ID */
+#define OV9640_MIDL_MAGIC      0xA2    /* low byte of mfg ID */
+
+#define OV9640_REG_TERM 0xFF   /* terminating list entry for reg */
+#define OV9640_VAL_TERM 0xFF   /* terminating list entry for val */
+
+/*
+ * The nominal xclk input frequency of the OV9640 is 24MHz, maximum
+ * frequency is 48MHz, and minimum frequency is 10MHz.
+ */
+#define OV9640_XCLK_MIN 10000000
+#define OV9640_XCLK_MAX 48000000
+#define OV9640_XCLK_NOM 24000000
+
+/* define a structure for ov9640 register initialization values */
+struct ov9640_reg {
+       unsigned char reg;
+       unsigned char val;
+};
+
+enum image_size { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+enum pixel_format { YUV, RGB565, RGB555 };
+
+#define NUM_IMAGE_SIZES 7
+#define NUM_PIXEL_FORMATS 3
+
+struct capture_size {
+       unsigned long width;
+       unsigned long height;
+};
+
+struct ov9640_platform_data {
+       /* Set power state, zero is off, non-zero is on. */
+       int (*power_set)(int power);
+       /* Default registers written after power-on or reset. */
+       const struct ov9640_reg *default_regs;
+       int (*ifparm)(struct v4l2_ifparm *p);
+};
+
+/*
+ * Array of image sizes supported by OV9640.  These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size ov9640_sizes[] = {
+       {   88,  72 },  /* QQCIF */
+       {  160, 120 },  /* QQVGA */
+       {  176, 144 },  /* QCIF */
+       {  320, 240 },  /* QVGA */
+       {  352, 288 },  /* CIF */
+       {  640, 480 },  /* VGA */
+       { 1280, 960 },  /* SXGA */
+};
+
+#endif /* ifndef OV9640_H */
index 68dc8d9eb24ee87e39a99d3543962b2453bd008f..e643f6bb81c1143b33fbb21b40c555bd7ae9f5e5 100644 (file)
@@ -50,6 +50,20 @@ config HTC_PASIC3
          HTC Magician devices, respectively. Actual functionality is
          handled by the leds-pasic3 and ds1wm drivers.
 
+config TWL4030_CORE
+       bool "Texas Instruments TWL4030/TPS659x0 Support"
+       depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3)
+       help
+         Say yes here if you have TWL4030 family chip on your board.
+         This core driver provides register access and IRQ handling
+         facilities, and registers devices for the various functions
+         so that function-specific drivers can bind to them.
+
+         These multi-function chips are found on many OMAP2 and OMAP3
+         boards, providing power management, RTC, GPIO, keypad, a
+         high speed USB OTG transceiver, an audio codec (on most
+         versions) and many other features.
+
 config MFD_TMIO
        bool
        default n
index 03ad239ecef0ba0fde5cc1dbebe579203953174f..5650e7b4e8eaaeccebaa25f54251ddefa83bc9e8 100644 (file)
@@ -12,6 +12,8 @@ obj-$(CONFIG_MFD_T7L66XB)     += t7l66xb.o
 obj-$(CONFIG_MFD_TC6387XB)     += tc6387xb.o
 obj-$(CONFIG_MFD_TC6393XB)     += tc6393xb.o
 
+obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o
+
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
 
 obj-$(CONFIG_MCP)              += mcp-core.o
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
new file mode 100644 (file)
index 0000000..767a811
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices
+ *
+ * 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/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/random.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
+ * Management and System Companion Device" chips originally designed for
+ * use in OMAP2 and OMAP 3 based systems.  Its control interfaces use I2C,
+ * often at around 3 Mbit/sec, including for interrupt handling.
+ *
+ * This driver core provides genirq support for the interrupts emitted,
+ * by the various modules, and exports register access primitives.
+ *
+ * FIXME this driver currently requires use of the first interrupt line
+ * (and associated registers).
+ */
+
+#define DRIVER_NAME                    "twl4030"
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODUEL)
+#define twl_has_bci()          true
+#else
+#define twl_has_bci()          false
+#endif
+
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad()       true
+#else
+#define twl_has_keypad()       false
+#endif
+
+#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
+#define twl_has_gpio() true
+#else
+#define twl_has_gpio() false
+#endif
+
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#define twl_has_madc() true
+#else
+#define twl_has_madc() false
+#endif
+
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc()  true
+#else
+#define twl_has_rtc()  false
+#endif
+
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb()  true
+#else
+#define twl_has_usb()  false
+#endif
+
+static inline void activate_irq(int irq)
+{
+#ifdef CONFIG_ARM
+       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
+        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+        */
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       /* same effect on other architectures */
+       set_irq_noprobe(irq);
+#endif
+}
+
+/* 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
+
+#define TWL4030_NUM_SLAVES             4
+
+
+/* Base Address defns for twl4030_map[] */
+
+/* subchip/slave 0 - USB ID */
+#define TWL4030_BASEADD_USB            0x0000
+
+/* subchip/slave 1 - 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
+
+/* subchip/slave 2 - 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
+
+/* subchip/slave 3 - POWER ID */
+#define TWL4030_BASEADD_BACKUP         0x0014
+#define TWL4030_BASEADD_INT            0x002E
+#define TWL4030_BASEADD_PM_MASTER      0x0036
+#define TWL4030_BASEADD_PM_RECEIVER    0x005B
+#define TWL4030_BASEADD_RTC            0x001C
+#define TWL4030_BASEADD_SECURED_REG    0x0000
+
+/* Triton Core internal information (END) */
+
+
+/* Few power values */
+#define R_CFG_BOOT                     0x05
+#define R_PROTECT_KEY                  0x0E
+
+/* access control values for R_PROTECT_KEY */
+#define KEY_UNLOCK1                    0xce
+#define KEY_UNLOCK2                    0xec
+#define KEY_LOCK                       0x00
+
+/* some fields in R_CFG_BOOT */
+#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)
+
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * struct twl4030_mod_iregs - TWL module IMR/ISR regs to mask/clear at init
+ * @mod_no: TWL4030 module number (e.g., TWL4030_MODULE_GPIO)
+ * @sih_ctrl: address of module SIH_CTRL register
+ * @reg_cnt: number of IMR/ISR regs
+ * @imrs: pointer to array of TWL module interrupt mask register indices
+ * @isrs: pointer to array of TWL module interrupt status register indices
+ *
+ * Ties together TWL4030 modules and lists of IMR/ISR registers to mask/clear
+ * during twl_init_irq().
+ */
+struct twl4030_mod_iregs {
+       const u8 mod_no;
+       const u8 sih_ctrl;
+       const u8 reg_cnt;
+       const u8 *imrs;
+       const u8 *isrs;
+};
+
+/* TWL4030 INT module interrupt mask registers */
+static const u8 __initconst twl4030_int_imr_regs[] = {
+       TWL4030_INT_PWR_IMR1,
+       TWL4030_INT_PWR_IMR2,
+};
+
+/* TWL4030 INT module interrupt status registers */
+static const u8 __initconst twl4030_int_isr_regs[] = {
+       TWL4030_INT_PWR_ISR1,
+       TWL4030_INT_PWR_ISR2,
+};
+
+/* TWL4030 INTERRUPTS module interrupt mask registers */
+static const u8 __initconst twl4030_interrupts_imr_regs[] = {
+       TWL4030_INTERRUPTS_BCIIMR1A,
+       TWL4030_INTERRUPTS_BCIIMR1B,
+       TWL4030_INTERRUPTS_BCIIMR2A,
+       TWL4030_INTERRUPTS_BCIIMR2B,
+};
+
+/* TWL4030 INTERRUPTS module interrupt status registers */
+static const u8 __initconst twl4030_interrupts_isr_regs[] = {
+       TWL4030_INTERRUPTS_BCIISR1A,
+       TWL4030_INTERRUPTS_BCIISR1B,
+       TWL4030_INTERRUPTS_BCIISR2A,
+       TWL4030_INTERRUPTS_BCIISR2B,
+};
+
+/* TWL4030 MADC module interrupt mask registers */
+static const u8 __initconst twl4030_madc_imr_regs[] = {
+       TWL4030_MADC_IMR1,
+       TWL4030_MADC_IMR2,
+};
+
+/* TWL4030 MADC module interrupt status registers */
+static const u8 __initconst twl4030_madc_isr_regs[] = {
+       TWL4030_MADC_ISR1,
+       TWL4030_MADC_ISR2,
+};
+
+/* TWL4030 keypad module interrupt mask registers */
+static const u8 __initconst twl4030_keypad_imr_regs[] = {
+       TWL4030_KEYPAD_KEYP_IMR1,
+       TWL4030_KEYPAD_KEYP_IMR2,
+};
+
+/* TWL4030 keypad module interrupt status registers */
+static const u8 __initconst twl4030_keypad_isr_regs[] = {
+       TWL4030_KEYPAD_KEYP_ISR1,
+       TWL4030_KEYPAD_KEYP_ISR2,
+};
+
+/* TWL4030 GPIO module interrupt mask registers */
+static const u8 __initconst twl4030_gpio_imr_regs[] = {
+       REG_GPIO_IMR1A,
+       REG_GPIO_IMR1B,
+       REG_GPIO_IMR2A,
+       REG_GPIO_IMR2B,
+       REG_GPIO_IMR3A,
+       REG_GPIO_IMR3B,
+};
+
+/* TWL4030 GPIO module interrupt status registers */
+static const u8 __initconst twl4030_gpio_isr_regs[] = {
+       REG_GPIO_ISR1A,
+       REG_GPIO_ISR1B,
+       REG_GPIO_ISR2A,
+       REG_GPIO_ISR2B,
+       REG_GPIO_ISR3A,
+       REG_GPIO_ISR3B,
+};
+
+/* TWL4030 modules that have IMR/ISR registers that must be masked/cleared */
+static const struct twl4030_mod_iregs __initconst twl4030_mod_regs[] = {
+       {
+               .mod_no   = TWL4030_MODULE_INT,
+               .sih_ctrl = TWL4030_INT_PWR_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_int_imr_regs),
+               .imrs     = twl4030_int_imr_regs,
+               .isrs     = twl4030_int_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_INTERRUPTS,
+               .sih_ctrl = TWL4030_INTERRUPTS_BCISIHCTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_interrupts_imr_regs),
+               .imrs     = twl4030_interrupts_imr_regs,
+               .isrs     = twl4030_interrupts_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_MADC,
+               .sih_ctrl = TWL4030_MADC_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_madc_imr_regs),
+               .imrs     = twl4030_madc_imr_regs,
+               .isrs     = twl4030_madc_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_KEYPAD,
+               .sih_ctrl = TWL4030_KEYPAD_KEYP_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_keypad_imr_regs),
+               .imrs     = twl4030_keypad_imr_regs,
+               .isrs     = twl4030_keypad_isr_regs,
+       },
+       {
+               .mod_no   = TWL4030_MODULE_GPIO,
+               .sih_ctrl = REG_GPIO_SIH_CTRL,
+               .reg_cnt  = ARRAY_SIZE(twl4030_gpio_imr_regs),
+               .imrs     = twl4030_gpio_imr_regs,
+               .isrs     = twl4030_gpio_isr_regs,
+       },
+};
+
+/*----------------------------------------------------------------*/
+
+/* is driver active, bound to a chip? */
+static bool inuse;
+
+/* Structure for each TWL4030 Slave */
+struct twl4030_client {
+       struct i2c_client *client;
+       u8 address;
+
+       /* max numb of i2c_msg required is for read =2 */
+       struct i2c_msg xfer_msg[2];
+
+       /* To lock access to xfer_msg */
+       struct mutex xfer_lock;
+};
+
+static struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES];
+
+
+/* mapping the module id to slave id and base address */
+struct twl4030mapping {
+       unsigned char sid;      /* Slave ID */
+       unsigned char base;     /* base address */
+};
+
+static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
+       /*
+        * NOTE:  don't change this table without updating the
+        * <linux/i2c/twl4030.h> defines for TWL4030_MODULE_*
+        * so they continue to match the order in this table.
+        */
+
+       { 0, TWL4030_BASEADD_USB },
+
+       { 1, TWL4030_BASEADD_AUDIO_VOICE },
+       { 1, TWL4030_BASEADD_GPIO },
+       { 1, TWL4030_BASEADD_INTBR },
+       { 1, TWL4030_BASEADD_PIH },
+       { 1, TWL4030_BASEADD_TEST },
+
+       { 2, TWL4030_BASEADD_KEYPAD },
+       { 2, TWL4030_BASEADD_MADC },
+       { 2, TWL4030_BASEADD_INTERRUPTS },
+       { 2, TWL4030_BASEADD_LED },
+       { 2, TWL4030_BASEADD_MAIN_CHARGE },
+       { 2, TWL4030_BASEADD_PRECHARGE },
+       { 2, TWL4030_BASEADD_PWM0 },
+       { 2, TWL4030_BASEADD_PWM1 },
+       { 2, TWL4030_BASEADD_PWMA },
+       { 2, TWL4030_BASEADD_PWMB },
+
+       { 3, TWL4030_BASEADD_BACKUP },
+       { 3, TWL4030_BASEADD_INT },
+       { 3, TWL4030_BASEADD_PM_MASTER },
+       { 3, TWL4030_BASEADD_PM_RECEIVER },
+       { 3, TWL4030_BASEADD_RTC },
+       { 3, TWL4030_BASEADD_SECURED_REG },
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * TWL4030 doesn't have PIH mask, hence dummy function for mask
+ * and unmask of the (eight) interrupts reported at that level ...
+ * masking is only available from SIH (secondary) modules.
+ */
+
+static void twl4030_i2c_ackirq(unsigned int irq)
+{
+}
+
+static void twl4030_i2c_disableint(unsigned int irq)
+{
+}
+
+static void twl4030_i2c_enableint(unsigned int irq)
+{
+}
+
+static struct irq_chip twl4030_irq_chip = {
+       .name   = "twl4030",
+       .ack    = twl4030_i2c_ackirq,
+       .mask   = twl4030_i2c_disableint,
+       .unmask = twl4030_i2c_enableint,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Exported Functions */
+
+/**
+ * twl4030_i2c_write - Writes a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes+1 containing data to write
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
+ * valid data starts at Offset 1.
+ *
+ * Returns the result of operation - 0 is success
+ */
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       int sid;
+       struct twl4030_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       twl = &twl4030_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /*
+        * [MSG1]: fill the register address data
+        * fill the data Tx buffer
+        */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = num_bytes + 1;
+       msg->flags = 0;
+       msg->buf = value;
+       /* over write the first byte of buffer with the register address */
+       *value = twl4030_map[mod_no].base + reg;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_write);
+
+/**
+ * twl4030_i2c_read - Reads a n bit register in TWL4030
+ * @mod_no: module number
+ * @value: an array of num_bytes containing data to be read
+ * @reg: register address (just offset will do)
+ * @num_bytes: number of bytes to transfer
+ *
+ * Returns result of operation - num_bytes is success else failure.
+ */
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+{
+       int ret;
+       u8 val;
+       int sid;
+       struct twl4030_client *twl;
+       struct i2c_msg *msg;
+
+       if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
+               pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
+               return -EPERM;
+       }
+       sid = twl4030_map[mod_no].sid;
+       twl = &twl4030_modules[sid];
+
+       if (unlikely(!inuse)) {
+               pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+               return -EPERM;
+       }
+       mutex_lock(&twl->xfer_lock);
+       /* [MSG1] fill the register address data */
+       msg = &twl->xfer_msg[0];
+       msg->addr = twl->address;
+       msg->len = 1;
+       msg->flags = 0; /* Read the register value */
+       val = twl4030_map[mod_no].base + reg;
+       msg->buf = &val;
+       /* [MSG2] fill the data rx buffer */
+       msg = &twl->xfer_msg[1];
+       msg->addr = twl->address;
+       msg->flags = I2C_M_RD;  /* Read the register value */
+       msg->len = num_bytes;   /* only n bytes */
+       msg->buf = value;
+       ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
+       mutex_unlock(&twl->xfer_lock);
+
+       /* i2cTransfer returns num messages.translate it pls.. */
+       if (ret >= 0)
+               ret = 0;
+       return ret;
+}
+EXPORT_SYMBOL(twl4030_i2c_read);
+
+/**
+ * twl4030_i2c_write_u8 - Writes a 8 bit register in TWL4030
+ * @mod_no: module number
+ * @value: the value to be written 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
+{
+
+       /* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
+       u8 temp_buffer[2] = { 0 };
+       /* offset 1 contains the data */
+       temp_buffer[1] = value;
+       return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_write_u8);
+
+/**
+ * twl4030_i2c_read_u8 - Reads a 8 bit register from TWL4030
+ * @mod_no: module number
+ * @value: the value read 8 bit
+ * @reg: register address (just offset will do)
+ *
+ * Returns result of operation - 0 is success
+ */
+int twl4030_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+       return twl4030_i2c_read(mod_no, value, reg, 1);
+}
+EXPORT_SYMBOL(twl4030_i2c_read_u8);
+
+/*----------------------------------------------------------------------*/
+
+static unsigned twl4030_irq_base;
+
+static struct completion irq_event;
+
+/*
+ * This thread processes interrupts reported by the Primary Interrupt Handler.
+ */
+static int twl4030_irq_thread(void *data)
+{
+       long irq = (long)data;
+       irq_desc_t *desc = irq_desc + irq;
+       static unsigned i2c_errors;
+       const static unsigned max_i2c_errors = 100;
+
+       current->flags |= PF_NOFREEZE;
+
+       while (!kthread_should_stop()) {
+               int ret;
+               int module_irq;
+               u8 pih_isr;
+
+               /* Wait for IRQ, then read PIH irq status (also blocking) */
+               wait_for_completion_interruptible(&irq_event);
+
+               ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
+                                         REG_PIH_ISR_P1);
+               if (ret) {
+                       pr_warning("%s: I2C error %d reading PIH ISR\n",
+                                       DRIVER_NAME, ret);
+                       if (++i2c_errors >= max_i2c_errors) {
+                               printk(KERN_ERR "Maximum I2C error count"
+                                               " exceeded.  Terminating %s.\n",
+                                               __func__);
+                               break;
+                       }
+                       complete(&irq_event);
+                       continue;
+               }
+
+               /* these handlers deal with the relevant SIH irq status */
+               local_irq_disable();
+               for (module_irq = twl4030_irq_base;
+                               pih_isr;
+                               pih_isr >>= 1, module_irq++) {
+                       if (pih_isr & 0x1) {
+                               irq_desc_t *d = irq_desc + module_irq;
+
+                               d->handle_irq(module_irq, d);
+                       }
+               }
+               local_irq_enable();
+
+               desc->chip->unmask(irq);
+       }
+
+       return 0;
+}
+
+/*
+ * do_twl4030_irq() is the desc->handle method for the twl4030 interrupt.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * Now we need to query the interrupt controller in the twl4030 to determine
+ * which module is generating the interrupt request.  However, we can't do i2c
+ * transactions in interrupt context, so we must defer that work to a kernel
+ * thread.  All we do here is acknowledge and mask the interrupt and wakeup
+ * the kernel thread.
+ */
+static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
+{
+       const unsigned int cpu = smp_processor_id();
+
+       /*
+        * Earlier this was desc->triggered = 1;
+        */
+       desc->status |= IRQ_LEVEL;
+
+       /*
+        * Acknowledge, clear _AND_ disable the interrupt.
+        */
+       desc->chip->ack(irq);
+
+       if (!desc->depth) {
+               kstat_cpu(cpu).irqs[irq]++;
+
+               complete(&irq_event);
+       }
+}
+
+static struct task_struct * __init start_twl4030_irq_thread(long irq)
+{
+       struct task_struct *thread;
+
+       init_completion(&irq_event);
+       thread = kthread_run(twl4030_irq_thread, (void *)irq, "twl4030-irq");
+       if (!thread)
+               pr_err("%s: could not create twl4030 irq %ld thread!\n",
+                      DRIVER_NAME, irq);
+
+       return thread;
+}
+
+/*----------------------------------------------------------------------*/
+
+static int add_children(struct twl4030_platform_data *pdata)
+{
+       struct platform_device  *pdev = NULL;
+       struct twl4030_client   *twl = NULL;
+       int                     status = 0;
+
+       if (twl_has_bci() && pdata->bci) {
+               twl = &twl4030_modules[3];
+
+               pdev = platform_device_alloc("twl4030_bci", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       status = platform_device_add_data(pdev, pdata->bci,
+                                       sizeof(*pdata->bci));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add bci data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               if (status == 0) {
+                       struct resource r = {
+                               .start = TWL4030_PWRIRQ_CHG_PRES,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create bci dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_gpio() && pdata->gpio) {
+               twl = &twl4030_modules[1];
+
+               pdev = platform_device_alloc("twl4030_gpio", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               /* more driver model init */
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       /* device_init_wakeup(&pdev->dev, 1); */
+
+                       status = platform_device_add_data(pdev, pdata->gpio,
+                                       sizeof(*pdata->gpio));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add gpio data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               /* GPIO module IRQ */
+               if (status == 0) {
+                       struct resource r = {
+                               .start = pdata->irq_base + 0,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create gpio dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_keypad() && pdata->keypad) {
+               pdev = platform_device_alloc("twl4030_keypad", -1);
+               if (pdev) {
+                       twl = &twl4030_modules[2];
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->keypad,
+                                       sizeof(*pdata->keypad));
+                       if (status < 0) {
+                               dev_dbg(&twl->client->dev,
+                                       "can't add keypad data, %d\n",
+                                       status);
+                               platform_device_put(pdev);
+                               goto err;
+                       }
+                       status = platform_device_add(pdev);
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                               "can't create keypad dev, %d\n",
+                                               status);
+                               goto err;
+                       }
+               } else {
+                       pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       if (twl_has_madc() && pdata->madc) {
+               pdev = platform_device_alloc("twl4030_madc", -1);
+               if (pdev) {
+                       twl = &twl4030_modules[2];
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->madc,
+                                       sizeof(*pdata->madc));
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                       "can't add madc data, %d\n",
+                                       status);
+                               goto err;
+                       }
+                       status = platform_device_add(pdev);
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                               "can't create madc dev, %d\n",
+                                               status);
+                               goto err;
+                       }
+               } else {
+                       pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+       }
+
+       if (twl_has_rtc()) {
+               twl = &twl4030_modules[3];
+
+               pdev = platform_device_alloc("twl4030_rtc", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+               } else {
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+               }
+
+               /*
+                * REVISIT platform_data here currently might use of
+                * "msecure" line ... but for now we just expect board
+                * setup to tell the chip "we are secure" at all times.
+                * Eventually, Linux might become more aware of such
+                * HW security concerns, and "least privilege".
+                */
+
+               /* RTC module IRQ */
+               if (status == 0) {
+                       struct resource r = {
+                               /* REVISIT don't hard-wire this stuff */
+                               .start = TWL4030_PWRIRQ_RTC,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create rtc dev, %d\n",
+                                       status);
+                       goto err;
+               }
+       }
+
+       if (twl_has_usb() && pdata->usb) {
+               twl = &twl4030_modules[0];
+
+               pdev = platform_device_alloc("twl4030_usb", -1);
+               if (!pdev) {
+                       pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
+                       status = -ENOMEM;
+                       goto err;
+               }
+
+               if (status == 0) {
+                       pdev->dev.parent = &twl->client->dev;
+                       device_init_wakeup(&pdev->dev, 1);
+                       status = platform_device_add_data(pdev, pdata->usb,
+                                       sizeof(*pdata->usb));
+                       if (status < 0) {
+                               platform_device_put(pdev);
+                               dev_dbg(&twl->client->dev,
+                                       "can't add usb data, %d\n",
+                                       status);
+                               goto err;
+                       }
+               }
+
+               if (status == 0) {
+                       struct resource r = {
+                               .start = TWL4030_PWRIRQ_USB_PRES,
+                               .flags = IORESOURCE_IRQ,
+                       };
+
+                       status = platform_device_add_resources(pdev, &r, 1);
+               }
+
+               if (status == 0)
+                       status = platform_device_add(pdev);
+
+               if (status < 0) {
+                       platform_device_put(pdev);
+                       dev_dbg(&twl->client->dev,
+                                       "can't create usb dev, %d\n",
+                                       status);
+               }
+       }
+
+err:
+       if (status)
+               pr_err("failed to add twl4030's children (status %d)\n", status);
+       return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * These three functions initialize the on-chip clock framework,
+ * letting it generate the right frequencies for USB, MADC, and
+ * other purposes.
+ */
+static inline int __init protect_pm_master(void)
+{
+       int e = 0;
+
+       e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static inline int __init unprotect_pm_master(void)
+{
+       int e = 0;
+
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
+                       R_PROTECT_KEY);
+       e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
+                       R_PROTECT_KEY);
+       return e;
+}
+
+static void __init clocks_init(void)
+{
+       int e = 0;
+       struct clk *osc;
+       u32 rate;
+       u8 ctrl = HFCLK_FREQ_26_MHZ;
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
+       if (cpu_is_omap2430())
+               osc = clk_get(NULL, "osc_ck");
+       else
+               osc = clk_get(NULL, "osc_sys_ck");
+#else
+       /* REVISIT for non-OMAP systems, pass the clock rate from
+        * board init code, using platform_data.
+        */
+       osc = ERR_PTR(-EIO);
+#endif
+       if (IS_ERR(osc)) {
+               printk(KERN_WARNING "Skipping twl4030 internal clock init and "
+                               "using bootloader value (unknown osc rate)\n");
+               return;
+       }
+
+       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();
+
+       if (e < 0)
+               pr_err("%s: clock init err [%d]\n", DRIVER_NAME, e);
+}
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * twl4030_i2c_clear_isr - clear TWL4030 SIH ISR regs via read + write
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ * @cor: value of the <module>_SIH_CTRL.COR bit (1 or 0)
+ *
+ * Either reads (cor == 1) or writes (cor == 0) to a TWL4030 interrupt
+ * status register to ensure that any prior interrupts are cleared.
+ * Returns the status from the I2C read operation.
+ */
+static int __init twl4030_i2c_clear_isr(u8 mod_no, u8 reg, u8 cor)
+{
+       u8 tmp;
+
+       return (cor) ? twl4030_i2c_read_u8(mod_no, &tmp, reg) :
+               twl4030_i2c_write_u8(mod_no, 0xff, reg);
+}
+
+/**
+ * twl4030_read_cor_bit - are TWL module ISRs cleared by reads or writes?
+ * @mod_no: TWL4030 module number
+ * @reg: register index to clear
+ *
+ * Returns 1 if the TWL4030 SIH interrupt status registers (ISRs) for
+ * the specified TWL module are cleared by reads, or 0 if cleared by
+ * writes.
+ */
+static int twl4030_read_cor_bit(u8 mod_no, u8 reg)
+{
+       u8 tmp = 0;
+
+       WARN_ON(twl4030_i2c_read_u8(mod_no, &tmp, reg) < 0);
+
+       tmp &= TWL4030_SIH_CTRL_COR_MASK;
+       tmp >>= __ffs(TWL4030_SIH_CTRL_COR_MASK);
+
+       return tmp;
+}
+
+/**
+ * twl4030_mask_clear_intrs - mask and clear all TWL4030 interrupts
+ * @t: pointer to twl4030_mod_iregs array
+ * @t_sz: ARRAY_SIZE(t) (starting at 1)
+ *
+ * Mask all TWL4030 interrupt mask registers (IMRs) and clear all
+ * interrupt status registers (ISRs).  No return value, but will WARN if
+ * any I2C operations fail.
+ */
+static void __init twl4030_mask_clear_intrs(const struct twl4030_mod_iregs *t,
+                                           const u8 t_sz)
+{
+       int i, j;
+
+       /*
+        * N.B. - further efficiency is possible here.  Eight I2C
+        * operations on BCI and GPIO modules are avoidable if I2C
+        * burst read/write transactions were implemented.  Would
+        * probably save about 1ms of boot time and a small amount of
+        * power.
+        */
+       for (i = 0; i < t_sz; i++) {
+               const struct twl4030_mod_iregs tmr = t[i];
+               int cor;
+
+               /* Are ISRs cleared by reads or writes? */
+               cor = twl4030_read_cor_bit(tmr.mod_no, tmr.sih_ctrl);
+
+               for (j = 0; j < tmr.reg_cnt; j++) {
+
+                       /* Mask interrupts at the TWL4030 */
+                       WARN_ON(twl4030_i2c_write_u8(tmr.mod_no, 0xff,
+                                                    tmr.imrs[j]) < 0);
+
+                       /* Clear TWL4030 ISRs */
+                       WARN_ON(twl4030_i2c_clear_isr(tmr.mod_no,
+                                                     tmr.isrs[j], cor) < 0);
+               }
+       }
+}
+
+
+static void twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
+{
+       int     i;
+
+       /*
+        * Mask and clear all TWL4030 interrupts since initially we do
+        * not have any TWL4030 module interrupt handlers present
+        */
+       twl4030_mask_clear_intrs(twl4030_mod_regs,
+                                ARRAY_SIZE(twl4030_mod_regs));
+
+       twl4030_irq_base = irq_base;
+
+       /* install an irq handler for each of the PIH modules */
+       for (i = irq_base; i < irq_end; i++) {
+               set_irq_chip_and_handler(i, &twl4030_irq_chip,
+                               handle_simple_irq);
+               activate_irq(i);
+       }
+
+       /* install an irq handler to demultiplex the TWL4030 interrupt */
+       set_irq_data(irq_num, start_twl4030_irq_thread(irq_num));
+       set_irq_chained_handler(irq_num, do_twl4030_irq);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int twl4030_remove(struct i2c_client *client)
+{
+       unsigned i;
+
+       /* FIXME undo twl_init_irq() */
+       if (twl4030_irq_base) {
+               dev_err(&client->dev, "can't yet clean up IRQs?\n");
+               return -ENOSYS;
+       }
+
+       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+               struct twl4030_client   *twl = &twl4030_modules[i];
+
+               if (twl->client && twl->client != client)
+                       i2c_unregister_device(twl->client);
+               twl4030_modules[i].client = NULL;
+       }
+       inuse = false;
+       return 0;
+}
+
+/* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
+static int
+twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int                             status;
+       unsigned                        i;
+       struct twl4030_platform_data    *pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_dbg(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
+               dev_dbg(&client->dev, "can't talk I2C?\n");
+               return -EIO;
+       }
+
+       if (inuse || twl4030_irq_base) {
+               dev_dbg(&client->dev, "driver is already in use\n");
+               return -EBUSY;
+       }
+
+       for (i = 0; i < TWL4030_NUM_SLAVES; i++) {
+               struct twl4030_client   *twl = &twl4030_modules[i];
+
+               twl->address = client->addr + i;
+               if (i == 0)
+                       twl->client = client;
+               else {
+                       twl->client = i2c_new_dummy(client->adapter,
+                                       twl->address);
+                       if (!twl->client) {
+                               dev_err(&twl->client->dev,
+                                       "can't attach client %d\n", i);
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+                       strlcpy(twl->client->name, id->name,
+                                       sizeof(twl->client->name));
+               }
+               mutex_init(&twl->xfer_lock);
+       }
+       inuse = true;
+
+       /* setup clock framework */
+       clocks_init();
+
+       /* Maybe init the T2 Interrupt subsystem */
+       if (client->irq
+                       && pdata->irq_base
+                       && pdata->irq_end > pdata->irq_base) {
+               twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end);
+               dev_info(&client->dev, "IRQ %d chains IRQs %d..%d\n",
+                               client->irq, pdata->irq_base, pdata->irq_end - 1);
+       }
+
+       status = add_children(pdata);
+fail:
+       if (status < 0)
+               twl4030_remove(client);
+       return status;
+}
+
+static const struct i2c_device_id twl4030_ids[] = {
+       { "twl4030", 0 },       /* "Triton 2" */
+       { "tps65950", 0 },      /* catalog version of twl4030 */
+       { "tps65930", 0 },      /* fewer LDOs and DACs; no charger */
+       { "tps65920", 0 },      /* fewer LDOs; no codec or charger */
+       { "twl5030", 0 },       /* T2 updated */
+       { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, twl4030_ids);
+
+/* One Client Driver , 4 Clients */
+static struct i2c_driver twl4030_driver = {
+       .driver.name    = DRIVER_NAME,
+       .id_table       = twl4030_ids,
+       .probe          = twl4030_probe,
+       .remove         = twl4030_remove,
+};
+
+static int __init twl4030_init(void)
+{
+       return i2c_add_driver(&twl4030_driver);
+}
+subsys_initcall(twl4030_init);
+
+static void __exit twl4030_exit(void)
+{
+       i2c_del_driver(&twl4030_driver);
+}
+module_exit(twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("I2C Core interface for TWL4030");
+MODULE_LICENSE("GPL");
index a726f3b01a6b36debf060b647c4384a4aab8f1b3..f0202eedd49bcb3169c901de1743100bc2dca43b 100644 (file)
@@ -409,11 +409,24 @@ config EEEPC_LAPTOP
        depends on BACKLIGHT_CLASS_DEVICE
        depends on HWMON
        depends on EXPERIMENTAL
+
        ---help---
          This driver supports the Fn-Fx keys on Eee PC laptops.
          It also adds the ability to switch camera/wlan on/off.
 
-         If you have an Eee PC laptop, say Y or M here.
+config OMAP_STI
+       bool "Serial Trace Interface support"
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
+       default n
+       help
+         Serial Trace Interface. The protocols suported for OMAP1/2/3 are
+         STI/CSTI/XTIv2 correspondingly.
+
+config OMAP_STI_CONSOLE
+       bool "STI console support"
+       depends on OMAP_STI
+       help
+         This enables a console driver by way of STI/XTI.
 
 config ENCLOSURE_SERVICES
        tristate "Enclosure Services"
index c6c13f60b4520124f7ce918069f37cdbda6e7806..b6167e79df77eb633938898b0ad3ab3ea0a8c439 100644 (file)
@@ -5,6 +5,7 @@ obj- := misc.o  # Dummy rule to force built-in.o to be made
 
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)    += hdpuftrs/
+obj-$(CONFIG_OMAP_STI)         += sti/
 obj-$(CONFIG_ASUS_LAPTOP)      += asus-laptop.o
 obj-$(CONFIG_EEEPC_LAPTOP)     += eeepc-laptop.o
 obj-$(CONFIG_MSI_LAPTOP)       += msi-laptop.o
diff --git a/drivers/misc/sti/Makefile b/drivers/misc/sti/Makefile
new file mode 100644 (file)
index 0000000..aee30bd
--- /dev/null
@@ -0,0 +1,8 @@
+ifeq ($(CONFIG_ARCH_OMAP3),y)
+obj-$(CONFIG_OMAP_STI) += sdti.o
+else
+obj-$(CONFIG_OMAP_STI) += sti.o sti-fifo.o
+obj-$(CONFIG_NET)      += sti-netlink.o
+endif
+
+obj-$(CONFIG_OMAP_STI_CONSOLE) += sti-console.o
diff --git a/drivers/misc/sti/sdti.c b/drivers/misc/sti/sdti.c
new file mode 100644 (file)
index 0000000..c35821d
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Support functions for OMAP3 SDTI (Serial Debug Tracing Interface)
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by: Roman Tereshonkov <roman.tereshonkov@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/sti.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#define SDTI_REVISION          0x000
+#define SDTI_SYSCONFIG         0x010
+#define SDTI_SYSSTATUS         0x014
+#define SDTI_WINCTRL           0x024
+#define SDTI_SCONFIG           0x028
+#define SDTI_TESTCTRL          0x02C
+#define SDTI_LOCK_ACCESS       0xFB0
+
+#define CPU1_TRACE_EN          0x01
+#define CPU2_TRACE_EN          0x02
+
+static struct clk *sdti_ck;
+unsigned long sti_base, sti_channel_base;
+static DEFINE_SPINLOCK(sdti_lock);
+
+void omap_sti_channel_write_trace(int len, int id, void *data,
+                               unsigned int channel)
+{
+       const u8 *tpntr = data;
+
+       spin_lock_irq(&sdti_lock);
+
+       sti_channel_writeb(id, channel);
+       while (len--)
+               sti_channel_writeb(*tpntr++, channel);
+       sti_channel_flush(channel);
+
+       spin_unlock_irq(&sdti_lock);
+}
+EXPORT_SYMBOL(omap_sti_channel_write_trace);
+
+static void omap_sdti_reset(void)
+{
+       int i;
+
+       sti_writel(0x02, SDTI_SYSCONFIG);
+
+       for (i = 0; i < 10000; i++)
+               if (sti_readl(SDTI_SYSSTATUS) & 1)
+                       break;
+       if (i == 10000)
+               printk(KERN_WARNING "XTI: no real reset\n");
+}
+
+static int __init omap_sdti_init(void)
+{
+       char buf[64];
+       int i;
+
+       sdti_ck = clk_get(NULL, "emu_per_alwon_ck");
+       if (IS_ERR(sdti_ck)) {
+               printk(KERN_ERR "Cannot get clk emu_per_alwon_ck\n");
+               return PTR_ERR(sdti_ck);
+       }
+       clk_enable(sdti_ck);
+
+       omap_sdti_reset();
+       sti_writel(0xC5ACCE55, SDTI_LOCK_ACCESS);
+
+       /* Claim SDTI */
+       sti_writel(1 << 30, SDTI_WINCTRL);
+       i = sti_readl(SDTI_WINCTRL);
+       if (!(i & (1 << 30)))
+               printk(KERN_WARNING "SDTI: cannot claim SDTI\n");
+
+       /* 4 bits dual, fclk/3 */
+       sti_writel(0x43, SDTI_SCONFIG);
+
+       /* CPU2 trace enable */
+       sti_writel(i | CPU2_TRACE_EN, SDTI_WINCTRL);
+       i = sti_readl(SDTI_WINCTRL);
+
+       /* Enable SDTI */
+       sti_writel((1 << 31) | (i & 0x3FFFFFFF), SDTI_WINCTRL);
+
+       i = sti_readl(SDTI_REVISION);
+       snprintf(buf, sizeof(buf), "OMAP SDTI support loaded (HW v%u.%u)\n",
+               (i >> 4) & 0x0f, i & 0x0f);
+       printk(KERN_INFO "%s", buf);
+       omap_sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+       return 0;
+}
+
+static void omap_sdti_exit(void)
+{
+       sti_writel(0, SDTI_WINCTRL);
+       clk_disable(sdti_ck);
+       clk_put(sdti_ck);
+}
+
+static int __devinit omap_sdti_probe(struct platform_device *pdev)
+{
+       struct resource *res, *cres;
+       unsigned int size;
+
+       if (pdev->num_resources != 2) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* SDTI base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+
+       /* Channel base */
+       cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (unlikely(!cres)) {
+               dev_err(&pdev->dev, "invalid channel mem resource\n");
+               return -ENODEV;
+       }
+
+       size = res->end - res->start;
+       sti_base = (unsigned long)ioremap(res->start, size);
+       if (unlikely(!sti_base))
+               return -ENODEV;
+
+       size = cres->end - cres->start;
+       sti_channel_base = (unsigned long)ioremap(cres->start, size);
+       if (unlikely(!sti_channel_base)) {
+               iounmap((void *)sti_base);
+               return -ENODEV;
+       }
+
+       return omap_sdti_init();
+}
+
+static int __devexit omap_sdti_remove(struct platform_device *pdev)
+{
+       iounmap((void *)sti_channel_base);
+       iounmap((void *)sti_base);
+       omap_sdti_exit();
+
+       return 0;
+}
+
+static struct platform_driver omap_sdti_driver = {
+       .probe          = omap_sdti_probe,
+       .remove         = __devexit_p(omap_sdti_remove),
+       .driver         = {
+               .name   = "sti",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap_sdti_module_init(void)
+{
+       return platform_driver_register(&omap_sdti_driver);
+}
+
+static void __exit omap_sdti_module_exit(void)
+{
+       platform_driver_unregister(&omap_sdti_driver);
+}
+subsys_initcall(omap_sdti_module_init);
+module_exit(omap_sdti_module_exit);
+
+MODULE_AUTHOR("Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-console.c b/drivers/misc/sti/sti-console.c
new file mode 100644 (file)
index 0000000..2062d23
--- /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 <mach/sti.h>
+#include <mach/board.h>
+
+#define DRV_NAME "sticon"
+
+static struct tty_driver *tty_driver;
+static DEFINE_SPINLOCK(sti_console_lock);
+static unsigned int sti_console_channel = -1;
+static int sti_line_done = -1;
+
+/*
+ * Write a string to any channel (including terminating NULL)
+ * Returns number of characters written.
+ */
+static int sti_channel_puts(const char *string, unsigned int channel, int len)
+{
+       int count = 0;
+
+       /*
+        * sti_line_done is needed to determine when we have reached the
+        * end of the line. write() has a tendency to hand us small
+        * strings which otherwise end up creating newlines.. we need to
+        * keep the channel open and in append mode until the line has
+        * been terminated.
+        */
+       if (sti_line_done != 0) {
+#ifdef __LITTLE_ENDIAN
+               sti_channel_writeb(0xc3, channel);
+#else
+               sti_channel_writeb(0xc0, channel);
+#endif
+               xchg(&sti_line_done, 0);
+       }
+
+       while (*string && count != len) {
+               char c = *string++;
+
+               count++;
+
+               if (c == '\n') {
+                       xchg(&sti_line_done, 1);
+                       sti_channel_writeb(0, channel);
+                       break;
+               } else
+                       sti_channel_writeb(c, channel);
+       }
+
+       if (sti_line_done)
+               sti_channel_flush(channel);
+
+       return count;
+}
+
+static int sti_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       return 0;
+}
+
+static int sti_tty_write(struct tty_struct *tty,
+                        const unsigned char *buf, int len)
+{
+       unsigned long flags;
+       int bytes;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       bytes = sti_channel_puts(buf, sti_console_channel, len);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+
+       return bytes;
+}
+
+static int sti_tty_write_room(struct tty_struct *tty)
+{
+       return 0x100000;
+}
+
+static int sti_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+static struct tty_operations sti_tty_ops = {
+       .open                   = sti_tty_open,
+       .write                  = sti_tty_write,
+       .write_room             = sti_tty_write_room,
+       .chars_in_buffer        = sti_tty_chars_in_buffer,
+};
+
+static void sti_console_write(struct console *c, const char *s, unsigned n)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sti_console_lock, flags);
+       sti_channel_puts(s, sti_console_channel, n);
+       spin_unlock_irqrestore(&sti_console_lock, flags);
+}
+
+static struct tty_driver *sti_console_device(struct console *c, int *index)
+{
+       *index = c->index;
+       return tty_driver;
+}
+
+static int sti_console_setup(struct console *c, char *opts)
+{
+       return 0;
+}
+
+static struct console sti_console = {
+       .name           = DRV_NAME,
+       .write          = sti_console_write,
+       .device         = sti_console_device,
+       .setup          = sti_console_setup,
+       .flags          = CON_PRINTBUFFER | CON_ENABLED,
+       .index          = -1,
+};
+
+static int __init sti_console_init(void)
+{
+       const struct omap_sti_console_config *info;
+
+       info = omap_get_config(OMAP_TAG_STI_CONSOLE,
+                              struct omap_sti_console_config);
+       if (info && info->enable) {
+               add_preferred_console(DRV_NAME, 0, NULL);
+
+               sti_console_channel = info->channel;
+       }
+
+       if (unlikely(sti_console_channel == -1))
+               return -EINVAL;
+
+       register_console(&sti_console);
+
+       return 0;
+}
+__initcall(sti_console_init);
+
+static int __init sti_tty_init(void)
+{
+       struct tty_driver *tty;
+       int ret;
+
+       tty = alloc_tty_driver(1);
+       if (!tty)
+               return -ENOMEM;
+
+       tty->name               = DRV_NAME;
+       tty->driver_name        = DRV_NAME;
+       tty->major              = 0;    /* dynamic major */
+       tty->minor_start        = 0;
+       tty->type               = TTY_DRIVER_TYPE_SYSTEM;
+       tty->subtype            = SYSTEM_TYPE_SYSCONS;
+       tty->init_termios       = tty_std_termios;
+
+       tty_set_operations(tty, &sti_tty_ops);
+
+       ret = tty_register_driver(tty);
+       if (ret) {
+               put_tty_driver(tty);
+               return ret;
+       }
+
+       tty_driver = tty;
+       return 0;
+}
+late_initcall(sti_tty_init);
+
+module_param(sti_console_channel, uint, 0);
+MODULE_PARM_DESC(sti_console_channel, "STI console channel");
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("OMAP STI console support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-fifo.c b/drivers/misc/sti/sti-fifo.c
new file mode 100644 (file)
index 0000000..1ea5b18
--- /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 <mach/sti.h>
+
+#define STI_READ_BUFFER_SIZE   1024
+#define sti_buf_pos(pos)       ((sti_crb->bufpos + (pos)) % \
+                                STI_READ_BUFFER_SIZE)
+
+static struct sti_cycle_buffer {
+       int bufpos;
+       int datalen;
+       unsigned char *buf;
+} *sti_crb;
+
+/**
+ * sti_read_packet - STI read packet (read an entire STI packet)
+ * @buf: Buffer to store the packet.
+ * @maxsize: Maximum size requested.
+ *
+ * This reads in a single completed STI packet from the RX FIFOs and
+ * places it in @buf for further processing.
+ *
+ * The return value is < 0 on error, and >= 0 for the number of bytes
+ * actually read. As per the STI specification, we require a 0xC1 to
+ * indicate the end of the packet, and we don't return the packet until
+ * we've read the entire thing in.
+ *
+ * Due to the size of the FIFOs, it's unrealistic to constantly drain
+ * this for 1 or 2 bytes at a time, so we assemble it here and return
+ * the whole thing.
+ */
+int sti_read_packet(unsigned char *buf, int maxsize)
+{
+       unsigned int pos;
+
+       if (unlikely(!buf))
+               return -EINVAL;
+       if (!sti_crb->datalen)
+               return 0;
+
+       pos = sti_buf_pos(sti_crb->datalen - 1);
+       /* End of packet */
+       if (sti_crb->buf[pos] == 0xC1) {
+               int i;
+
+               for (i = 0; i < sti_crb->datalen && i < maxsize; i++) {
+                       pos = sti_buf_pos(i);
+                       buf[i] = sti_crb->buf[pos];
+               }
+
+               sti_crb->bufpos = sti_buf_pos(i);
+               sti_crb->datalen -= i;
+
+               return i;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_read_packet);
+
+static void sti_fifo_irq(unsigned long arg)
+{
+       /* If there is data read it */
+       while (!(sti_readl(STI_RX_STATUS) & STI_RXFIFO_EMPTY)) {
+               unsigned int pos = sti_buf_pos(sti_crb->datalen);
+
+               sti_crb->buf[pos] = sti_readl(STI_RX_DR);
+               sti_crb->datalen++;
+       }
+
+       sti_ack_irq(STI_RX_INT);
+}
+
+static int __init sti_fifo_init(void)
+{
+       unsigned int size;
+       int ret;
+
+       size = sizeof(struct sti_cycle_buffer) + STI_READ_BUFFER_SIZE;
+       sti_crb = kmalloc(size, GFP_KERNEL);
+       if (!sti_crb)
+               return -ENOMEM;
+
+       sti_crb->bufpos = sti_crb->datalen = 0;
+       sti_crb->buf = (unsigned char *)(sti_crb + sizeof(*sti_crb));
+
+       ret = sti_request_irq(STI_RX_INT, sti_fifo_irq, 0);
+       if (ret != 0)
+               kfree(sti_crb);
+
+       return ret;
+}
+
+static void __exit sti_fifo_exit(void)
+{
+       sti_free_irq(STI_RX_INT);
+       kfree(sti_crb);
+}
+
+module_init(sti_fifo_init);
+module_exit(sti_fifo_exit);
+
+MODULE_AUTHOR("Paul Mundt, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/sti/sti-netlink.c b/drivers/misc/sti/sti-netlink.c
new file mode 100644 (file)
index 0000000..f1f8a48
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * OMAP STI/XTI communications interface via netlink socket.
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netlink.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/mutex.h>
+#include <net/sock.h>
+#include <mach/sti.h>
+
+static struct sock *sti_sock;
+static DEFINE_MUTEX(sti_netlink_mutex);
+
+enum {
+       STI_READ,
+       STI_WRITE,
+};
+
+static int sti_netlink_read(int pid, int seq, void *payload, int size)
+{
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       int ret, len = NLMSG_SPACE(size);
+       unsigned char *tail;
+
+       skb = alloc_skb(len, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       tail = skb->tail;
+       nlh = NLMSG_PUT(skb, pid, seq, STI_READ,
+                       len - (sizeof(struct nlmsghdr)));
+       nlh->nlmsg_flags = 0;
+       memcpy(NLMSG_DATA(nlh), payload, size);
+       nlh->nlmsg_len = skb->tail - tail;
+
+       ret = netlink_unicast(sti_sock, skb, pid, MSG_DONTWAIT);
+       if (ret > 0)
+               ret = 0;
+
+       return ret;
+
+nlmsg_failure:
+       if (skb)
+               kfree_skb(skb);
+
+       return -EINVAL;
+}
+
+/*
+ * We abuse nlmsg_type and nlmsg_flags for our purposes.
+ *
+ * The ID is encoded into the upper 8 bits of the nlmsg_type, while the
+ * channel number is encoded into the upper 8 bits of the nlmsg_flags.
+ */
+static int sti_netlink_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       void *data;
+       u8 chan, id;
+       int size, ret = 0, len = 0;
+
+       data    = NLMSG_DATA(nlh);
+       chan    = (nlh->nlmsg_flags >> 8) & 0xff;
+       id      = (nlh->nlmsg_type  >> 8) & 0xff;
+       size    = (int)(nlh->nlmsg_len - ((char *)data - (char *)nlh));
+
+       switch (nlh->nlmsg_type & 0xff) {
+       case STI_WRITE:
+               sti_channel_write_trace(size, id, data, chan);
+               break;
+       case STI_READ:
+               data = kmalloc(size, GFP_KERNEL);
+               if (!data)
+                       return -ENOMEM;
+               memset(data, 0, size);
+
+               len = sti_read_packet(data, size);
+               ret = sti_netlink_read(NETLINK_CB(skb).pid, nlh->nlmsg_seq,
+                                      data, len);
+               kfree(data);
+               break;
+       default:
+               return -ENOTTY;
+       }
+
+       return ret;
+}
+
+static int sti_netlink_receive_skb(struct sk_buff *skb)
+{
+       while (skb->len >= NLMSG_SPACE(0)) {
+               struct nlmsghdr *nlh;
+               u32 rlen;
+               int ret;
+
+               nlh = (struct nlmsghdr *)skb->data;
+               if (nlh->nlmsg_len < sizeof(struct nlmsghdr) ||
+                   skb->len < nlh->nlmsg_len)
+                       break;
+
+               rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (rlen > skb->len)
+                       rlen = skb->len;
+
+               ret = sti_netlink_receive_msg(skb, nlh);
+               if (ret)
+                       netlink_ack(skb, nlh, -ret);
+               else if (nlh->nlmsg_flags & NLM_F_ACK)
+                       netlink_ack(skb, nlh, 0);
+
+               skb_pull(skb, rlen);
+       }
+
+       return 0;
+}
+
+static void sti_netlink_receive(struct sk_buff *skb)
+{
+       if (!mutex_trylock(&sti_netlink_mutex))
+               return;
+
+       sti_netlink_receive_skb(skb);
+       mutex_unlock(&sti_netlink_mutex);
+}
+
+static int __init sti_netlink_init(void)
+{
+       sti_sock = netlink_kernel_create(&init_net, NETLINK_USERSOCK, 0,
+                                        sti_netlink_receive, NULL,
+                                        THIS_MODULE);
+       if (!sti_sock) {
+               printk(KERN_ERR "STI: Failed to create netlink socket\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+module_init(sti_netlink_init);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("STI netlink-driven communications interface");
diff --git a/drivers/misc/sti/sti.c b/drivers/misc/sti/sti.c
new file mode 100644 (file)
index 0000000..518298b
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Support functions for OMAP STI/XTI (Serial Tracing Interface)
+ *
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Written by: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * STI initialization code and channel handling
+ * from Juha Yrjölä <juha.yrjola@nokia.com>.
+ *
+ * XTI initialization
+ * from Roman Tereshonkov <roman.tereshonkov@nokia.com>.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/sti.h>
+#include <asm/byteorder.h>
+
+static struct clk *sti_ck;
+void __iomem *sti_base, *sti_channel_base;
+static unsigned long sti_kern_mask = STIEn;
+static unsigned long sti_irq_mask = STI_IRQSTATUS_MASK;
+static DEFINE_SPINLOCK(sti_lock);
+
+static struct sti_irqdesc {
+       irqreturn_t (*func)(unsigned long);
+       unsigned long data;
+} ____cacheline_aligned sti_irq_desc[STI_NR_IRQS];
+
+void sti_channel_write_trace(int len, int id, void *data, unsigned int channel)
+{
+       const u8 *tpntr = data;
+
+       sti_channel_writeb(id, channel);
+
+       if (cpu_is_omap16xx())
+               /* Check u32 boundary */
+               if (!((u32)data & (STI_PERCHANNEL_SIZE - 1)) &&
+                    (len >= STI_PERCHANNEL_SIZE)) {
+                       const u32 *asrc = data;
+
+                       do {
+                               sti_channel_writel(cpu_to_be32(*asrc++),
+                                                  channel);
+                               len -= STI_PERCHANNEL_SIZE;
+                       } while (len >= STI_PERCHANNEL_SIZE);
+
+                       tpntr = (const u8 *)asrc;
+               }
+
+       while (len--)
+               sti_channel_writeb(*tpntr++, channel);
+
+       sti_channel_flush(channel);
+}
+EXPORT_SYMBOL(sti_channel_write_trace);
+
+void sti_enable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+       sti_writel(1 << id, STI_IRQSETEN);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_enable_irq);
+
+void sti_disable_irq(unsigned int id)
+{
+       spin_lock_irq(&sti_lock);
+
+       if (cpu_is_omap16xx())
+               sti_writel(1 << id, STI_IRQCLREN);
+       else if (cpu_is_omap24xx())
+               sti_writel(sti_readl(STI_IRQSETEN) & ~(1 << id), STI_IRQSETEN);
+       else
+               BUG();
+
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_disable_irq);
+
+void sti_ack_irq(unsigned int id)
+{
+       /* Even though the clear state is 0, we have to write 1 to clear */
+       sti_writel(1 << id, STI_IRQSTATUS);
+}
+EXPORT_SYMBOL(sti_ack_irq);
+
+int sti_request_irq(unsigned int irq, void *handler, unsigned long arg)
+{
+       struct sti_irqdesc *desc;
+
+       if (unlikely(!handler || irq > STI_NR_IRQS))
+               return -EINVAL;
+
+       desc = sti_irq_desc + irq;
+       if (unlikely(desc->func)) {
+               printk(KERN_WARNING "STI: Attempting to request in-use IRQ "
+                                   "%d, consider fixing your code..\n", irq);
+               return -EBUSY;
+       }
+
+       desc->func = handler;
+       desc->data = arg;
+
+       sti_enable_irq(irq);
+       return 0;
+}
+EXPORT_SYMBOL(sti_request_irq);
+
+void sti_free_irq(unsigned int irq)
+{
+       struct sti_irqdesc *desc = sti_irq_desc + irq;
+
+       if (unlikely(irq > STI_NR_IRQS))
+               return;
+
+       sti_disable_irq(irq);
+
+       desc->func = NULL;
+       desc->data = 0;
+}
+EXPORT_SYMBOL(sti_free_irq);
+
+/*
+ * This is a bit heavy, so normally we would defer this to a tasklet.
+ * Unfortunately tasklets are too slow for the RX FIFO interrupt (and
+ * possibly some others), so we just do the irqdesc walking here.
+ */
+static irqreturn_t sti_interrupt(int irq, void *dev_id)
+{
+       int ret = IRQ_NONE;
+       u16 status;
+       int i;
+
+       status = sti_readl(STI_IRQSTATUS) & sti_irq_mask;
+
+       for (i = 0; status; i++) {
+               struct sti_irqdesc *desc = sti_irq_desc + i;
+               u16 id = 1 << i;
+
+               if (!(status & id))
+                       continue;
+
+               if (likely(desc && desc->func))
+                       ret |= desc->func(desc->data);
+               if (unlikely(ret == IRQ_NONE)) {
+                       printk("STI: spurious interrupt (id %d)\n", id);
+                       sti_disable_irq(i);
+                       sti_ack_irq(i);
+                       ret = IRQ_HANDLED;
+               }
+
+               status &= ~id;
+       }
+
+       return IRQ_RETVAL(ret);
+}
+
+static void omap_sti_reset(void)
+{
+       int i;
+
+       /* Reset STI module */
+       sti_writel(0x02, STI_SYSCONFIG);
+
+       /* Wait a while for the STI module to complete its reset */
+       for (i = 0; i < 10000; i++)
+               if (sti_readl(STI_SYSSTATUS) & 1)
+                       break;
+}
+
+static int __init sti_init(void)
+{
+       char buf[64];
+       int i;
+
+       if (cpu_is_omap16xx()) {
+               /* Release ARM Rhea buses peripherals enable */
+               sti_writel(sti_readl(ARM_RSTCT2) | 0x0001, ARM_RSTCT2);
+
+               /* Enable TC1_CK (functional clock) */
+               sti_ck = clk_get(NULL, "tc1_ck");
+       } else if (cpu_is_omap24xx())
+               /* Enable emulation tools clock */
+               sti_ck = clk_get(NULL, "emul_ck");
+
+       if (IS_ERR(sti_ck))
+               return PTR_ERR(sti_ck);
+
+       clk_enable(sti_ck);
+
+       /* Reset STI module */
+       omap_sti_reset();
+
+       /* Enable STI */
+       sti_trace_enable(MPUCmdEn);
+
+       /* Change to custom serial protocol */
+       sti_writel(0x01, STI_SERIAL_CFG);
+
+       /* Set STI clock control register to normal mode */
+       sti_writel(0x00, STI_CLK_CTRL);
+
+       i = sti_readl(STI_REVISION);
+       snprintf(buf, sizeof(buf), "OMAP STI support loaded (HW v%u.%u)\n",
+               (i >> 4) & 0x0f, i & 0x0f);
+       printk(KERN_INFO "%s", buf);
+
+       sti_channel_write_trace(strlen(buf), 0xc3, buf, 239);
+
+       return 0;
+}
+
+static void sti_exit(void)
+{
+       u32 tmp;
+
+       /*
+        * This should have already been done by reset, but we switch off
+        * STI entirely just for added sanity..
+        */
+       tmp = sti_readl(STI_ER);
+       tmp &= ~STIEn;
+       sti_writel(tmp, STI_ER);
+
+       clk_disable(sti_ck);
+       clk_put(sti_ck);
+}
+
+static void __sti_trace_enable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_ER);
+       tmp |= sti_kern_mask | event;
+       sti_writel(tmp, STI_ER);
+}
+
+int sti_trace_enable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask |= event;
+       __sti_trace_enable(event);
+       spin_unlock_irq(&sti_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(sti_trace_enable);
+
+static void __sti_trace_disable(int event)
+{
+       u32 tmp;
+
+       tmp = sti_readl(STI_DR);
+
+       if (cpu_is_omap16xx()) {
+               tmp |= event;
+               tmp &= ~sti_kern_mask;
+       } else if (cpu_is_omap24xx()) {
+               tmp &= ~event;
+               tmp |= sti_kern_mask;
+       } else
+               BUG();
+
+       sti_writel(tmp, STI_DR);
+}
+
+void sti_trace_disable(int event)
+{
+       spin_lock_irq(&sti_lock);
+       sti_kern_mask &= ~event;
+       __sti_trace_disable(event);
+       spin_unlock_irq(&sti_lock);
+}
+EXPORT_SYMBOL(sti_trace_disable);
+
+static ssize_t
+sti_trace_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%08lx\n", sti_readl(STI_ER));
+}
+
+static ssize_t
+sti_trace_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       int evt = simple_strtoul(buf, NULL, 0);
+       int mask = ~evt;
+
+       spin_lock_irq(&sti_lock);
+       __sti_trace_disable(mask);
+       __sti_trace_enable(evt);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(trace, S_IRUGO | S_IWUSR, sti_trace_show, sti_trace_store);
+
+static ssize_t
+sti_imask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%04lx\n", sti_irq_mask);
+}
+
+static ssize_t
+sti_imask_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       spin_lock_irq(&sti_lock);
+       sti_irq_mask = simple_strtoul(buf, NULL, 0);
+       spin_unlock_irq(&sti_lock);
+
+       return count;
+}
+static DEVICE_ATTR(imask, S_IRUGO | S_IWUSR, sti_imask_show, sti_imask_store);
+
+static int __devinit sti_probe(struct platform_device *pdev)
+{
+       struct resource *res, *cres;
+       unsigned int size;
+       int ret;
+
+       if (pdev->num_resources != 3) {
+               dev_err(&pdev->dev, "invalid number of resources: %d\n",
+                       pdev->num_resources);
+               return -ENODEV;
+       }
+
+       /* STI base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (unlikely(!res)) {
+               dev_err(&pdev->dev, "invalid mem resource\n");
+               return -ENODEV;
+       }
+
+       /* Channel base */
+       cres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (unlikely(!cres)) {
+               dev_err(&pdev->dev, "invalid channel mem resource\n");
+               return -ENODEV;
+       }
+
+       ret = device_create_file(&pdev->dev, &dev_attr_trace);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = device_create_file(&pdev->dev, &dev_attr_imask);
+       if (unlikely(ret != 0))
+               goto err;
+
+       size = res->end - res->start + 1;
+       sti_base = ioremap(res->start, size);
+       if (!sti_base) {
+               ret = -ENOMEM;
+               goto err_badremap;
+       }
+
+       size = cres->end - cres->start + 1;
+       sti_channel_base = ioremap(cres->start, size);
+       if (!sti_channel_base) {
+               iounmap(sti_base);
+               ret = -ENOMEM;
+               goto err_badremap;
+       }
+
+       ret = request_irq(platform_get_irq(pdev, 0), sti_interrupt,
+                         IRQF_DISABLED, "sti", NULL);
+       if (unlikely(ret != 0))
+               goto err_badirq;
+
+       return sti_init();
+
+err_badirq:
+       iounmap(sti_channel_base);
+       iounmap(sti_base);
+err_badremap:
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+err:
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+
+       return ret;
+}
+
+static int __devexit sti_remove(struct platform_device *pdev)
+{
+       unsigned int irq = platform_get_irq(pdev, 0);
+
+       iounmap(sti_channel_base);
+       iounmap(sti_base);
+
+       device_remove_file(&pdev->dev, &dev_attr_trace);
+       device_remove_file(&pdev->dev, &dev_attr_imask);
+       free_irq(irq, NULL);
+       sti_exit();
+
+       return 0;
+}
+
+static struct platform_driver sti_driver = {
+       .probe          = sti_probe,
+       .remove         = __devexit_p(sti_remove),
+       .driver         = {
+               .name   = "sti",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sti_module_init(void)
+{
+       return platform_driver_register(&sti_driver);
+}
+
+static void __exit sti_module_exit(void)
+{
+       platform_driver_unregister(&sti_driver);
+}
+subsys_initcall(sti_module_init);
+module_exit(sti_module_exit);
+
+MODULE_AUTHOR("Paul Mundt, Juha Yrjölä, Roman Tereshonkov");
+MODULE_LICENSE("GPL");
index ea8d7a3490d9b7ee575f23587721337ac8cbbc4a..bf90350d49875da2fb07c1e0aea703922d0419a6 100644 (file)
@@ -67,8 +67,9 @@ config MMC_RICOH_MMC
 
 config MMC_OMAP
        tristate "TI OMAP Multimedia Card Interface support"
-       depends on ARCH_OMAP
+       depends on ARCH_OMAP1 || (ARCH_OMAP2 && ARCH_OMAP2420)
        select TPS65010 if MACH_OMAP_H2
+       select OMAP_GPIO_SWITCH if MACH_NOKIA_N800
        help
          This selects the TI OMAP Multimedia card Interface.
          If you have an OMAP board with a Multimedia Card slot,
@@ -76,6 +77,17 @@ config MMC_OMAP
 
          If unsure, say N.
 
+config MMC_OMAP_HS
+       tristate "TI OMAP High Speed Multimedia Card Interface support"
+       depends on (ARCH_OMAP2 && ARCH_OMAP2430) || ARCH_OMAP3
+       select TWL4030_CORE if MACH_OMAP_2430SDP || MACH_OMAP_3430SDP
+       help
+         This selects the TI OMAP High Speed Multimedia card Interface.
+         If you have an OMAP2(2430) or OMAP3 board with a Multimedia Card slot,
+         say Y or M here.
+
+         If unsure, say N.
+
 config MMC_WBSD
        tristate "Winbond W83L51xD SD/MMC Card Interface support"
        depends on ISA_DMA_API
index c794cc5ce44220f94fc4d9351725bef5594b3711..ba477bc0f1b40bbd15daf40584964c3b85dda1e8 100644 (file)
@@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_RICOH_MMC)   += ricoh_mmc.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
+obj-$(CONFIG_MMC_OMAP_HS)      += omap_hsmmc.o
 obj-$(CONFIG_MMC_AT91)         += at91_mci.o
 obj-$(CONFIG_MMC_ATMELMCI)     += atmel-mci.o
 obj-$(CONFIG_MMC_TIFM_SD)      += tifm_sd.o
index c16028872bbbc0b19c23c8cdb895ad91a22fa3a4..c6544d2d072a131c06b97bc1af15fb524be69be7 100644 (file)
@@ -172,7 +172,7 @@ struct mmc_omap_host {
        struct omap_mmc_platform_data *pdata;
 };
 
-void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
+static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
 {
        unsigned long tick_ns;
 
@@ -182,7 +182,7 @@ void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
        }
 }
 
-void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
+static void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
 {
        unsigned long flags;
 
@@ -1015,7 +1015,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data
        }
 
        if (is_read) {
-               if (host->id == 1) {
+               if (host->id == 0) {
                        sync_dev = OMAP_DMA_MMC_RX;
                        dma_dev_name = "MMC1 read";
                } else {
@@ -1023,7 +1023,7 @@ static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data
                        dma_dev_name = "MMC2 read";
                }
        } else {
-               if (host->id == 1) {
+               if (host->id == 0) {
                        sync_dev = OMAP_DMA_MMC_TX;
                        dma_dev_name = "MMC1 write";
                } else {
@@ -1317,7 +1317,7 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
        host->slots[id] = slot;
 
        mmc->caps = 0;
-       if (host->pdata->conf.wire4)
+       if (host->pdata->slots[id].wire4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        mmc->ops = &mmc_omap_ops;
@@ -1451,11 +1451,14 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
        host->irq = irq;
 
        host->use_dma = 1;
+       host->dev->dma_mask = &pdata->dma_mask;
        host->dma_ch = -1;
 
        host->irq = irq;
        host->phys_base = host->mem_res->start;
-       host->virt_base = (void __iomem *) IO_ADDRESS(host->phys_base);
+       host->virt_base = ioremap(res->start, res->end - res->start + 1);
+       if (!host->virt_base)
+               goto err_ioremap;
 
        if (cpu_is_omap24xx()) {
                host->iclk = clk_get(&pdev->dev, "mmc_ick");
@@ -1510,6 +1513,8 @@ err_free_iclk:
                clk_put(host->iclk);
        }
 err_free_mmc_host:
+       iounmap(host->virt_base);
+err_ioremap:
        kfree(host);
 err_free_mem_region:
        release_mem_region(res->start, res->end - res->start + 1);
@@ -1536,6 +1541,7 @@ static int mmc_omap_remove(struct platform_device *pdev)
        if (host->fclk && !IS_ERR(host->fclk))
                clk_put(host->fclk);
 
+       iounmap(host->virt_base);
        release_mem_region(pdev->resource[0].start,
                           pdev->resource[0].end - pdev->resource[0].start + 1);
 
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
new file mode 100644 (file)
index 0000000..00b1b68
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * drivers/mmc/host/omap_hsmmc.c
+ *
+ * Driver for OMAP2430/3430 MMC controller.
+ *
+ * Copyright (C) 2007 Texas Instruments.
+ *
+ * Authors:
+ *     Syed Mohammed Khasim    <x0khasim@ti.com>
+ *     Madhusudhan             <madhu.cr@ti.com>
+ *     Mohit Jalori            <mjalori@ti.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+#include <asm/dma.h>
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/mmc.h>
+#include <mach/cpu.h>
+
+/* OMAP HSMMC Host Controller Registers */
+#define OMAP_HSMMC_SYSCONFIG   0x0010
+#define OMAP_HSMMC_CON         0x002C
+#define OMAP_HSMMC_BLK         0x0104
+#define OMAP_HSMMC_ARG         0x0108
+#define OMAP_HSMMC_CMD         0x010C
+#define OMAP_HSMMC_RSP10       0x0110
+#define OMAP_HSMMC_RSP32       0x0114
+#define OMAP_HSMMC_RSP54       0x0118
+#define OMAP_HSMMC_RSP76       0x011C
+#define OMAP_HSMMC_DATA                0x0120
+#define OMAP_HSMMC_HCTL                0x0128
+#define OMAP_HSMMC_SYSCTL      0x012C
+#define OMAP_HSMMC_STAT                0x0130
+#define OMAP_HSMMC_IE          0x0134
+#define OMAP_HSMMC_ISE         0x0138
+#define OMAP_HSMMC_CAPA                0x0140
+
+#define VS18                   (1<<26)
+#define VS30                   (1<<25)
+#define SDVS18                 (0x5<<9)
+#define SDVS30                 (0x6<<9)
+#define SDVSCLR                        0xFFFFF1FF
+#define SDVSDET                        0x00000400
+#define AUTOIDLE               0x1
+#define SDBP                   (1<<8)
+#define DTO                    0xe
+#define ICE                    0x1
+#define ICS                    0x2
+#define CEN                    (1<<2)
+#define CLKD_MASK              0x0000FFC0
+#define INT_EN_MASK            0x307F0033
+#define INIT_STREAM            (1<<1)
+#define DP_SELECT              (1<<21)
+#define DDIR                   (1<<4)
+#define DMA_EN                 0x1
+#define MSBS                   1<<5
+#define BCE                    1<<1
+#define FOUR_BIT               1 << 1
+#define CC                     0x1
+#define TC                     0x02
+#define OD                     0x1
+#define ERR                    (1 << 15)
+#define CMD_TIMEOUT            (1 << 16)
+#define DATA_TIMEOUT           (1 << 20)
+#define CMD_CRC                        (1 << 17)
+#define DATA_CRC               (1 << 21)
+#define CARD_ERR               (1 << 28)
+#define STAT_CLEAR             0xFFFFFFFF
+#define INIT_STREAM_CMD                0x00000000
+#define DUAL_VOLT_OCR_BIT      7
+#define SRC                    (1 << 25)
+#define SRD                    (1 << 26)
+
+/*
+ * FIXME: Most likely all the data using these _DEVID defines should come
+ * from the platform_data, or implemented in controller and slot specific
+ * functions.
+ */
+#define OMAP_MMC1_DEVID                0
+#define OMAP_MMC2_DEVID                1
+
+#define OMAP_MMC_DATADIR_NONE  0
+#define OMAP_MMC_DATADIR_READ  1
+#define OMAP_MMC_DATADIR_WRITE 2
+#define MMC_TIMEOUT_MS         20
+#define OMAP_MMC_MASTER_CLOCK  96000000
+#define DRIVER_NAME            "mmci-omap"
+
+/*
+ * One controller can have multiple slots, like on some omap boards using
+ * omap.c controller driver. Luckily this is not currently done on any known
+ * omap_hsmmc.c device.
+ */
+#define mmc_slot(host)         (host->pdata->slots[host->slot_id])
+
+/*
+ * MMC Host controller read/write API's
+ */
+#define OMAP_HSMMC_READ(base, reg)     \
+       __raw_readl((base) + OMAP_HSMMC_##reg)
+
+#define OMAP_HSMMC_WRITE(base, reg, val) \
+       __raw_writel((val), (base) + OMAP_HSMMC_##reg)
+
+struct mmc_omap_host {
+       struct  device          *dev;
+       struct  mmc_host        *mmc;
+       struct  mmc_request     *mrq;
+       struct  mmc_command     *cmd;
+       struct  mmc_data        *data;
+       struct  clk             *fclk;
+       struct  clk             *iclk;
+       struct  clk             *dbclk;
+       struct  semaphore       sem;
+       struct  work_struct     mmc_carddetect_work;
+       void    __iomem         *base;
+       resource_size_t         mapbase;
+       unsigned int            id;
+       unsigned int            dma_len;
+       unsigned int            dma_dir;
+       unsigned char           bus_mode;
+       unsigned char           datadir;
+       u32                     *buffer;
+       u32                     bytesleft;
+       int                     suspended;
+       int                     irq;
+       int                     carddetect;
+       int                     use_dma, dma_ch;
+       int                     initstr;
+       int                     slot_id;
+       int                     dbclk_enabled;
+       struct  omap_mmc_platform_data  *pdata;
+};
+
+/*
+ * Stop clock to the card
+ */
+static void omap_mmc_stop_clock(struct mmc_omap_host *host)
+{
+       OMAP_HSMMC_WRITE(host->base, SYSCTL,
+               OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
+       if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
+               dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
+}
+
+/*
+ * Send init stream sequence to card
+ * before sending IDLE command
+ */
+static void send_init_stream(struct mmc_omap_host *host)
+{
+       int reg = 0;
+       unsigned long timeout;
+
+       disable_irq(host->irq);
+       OMAP_HSMMC_WRITE(host->base, CON,
+               OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
+       OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
+
+       timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+       while ((reg != CC) && time_before(jiffies, timeout))
+               reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
+
+       OMAP_HSMMC_WRITE(host->base, CON,
+               OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
+       enable_irq(host->irq);
+}
+
+static inline
+int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
+{
+       if (host->pdata->slots[host->slot_id].get_cover_state)
+               return host->pdata->slots[host->slot_id].get_cover_state(host->dev, host->slot_id);
+       return 1;
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
+       struct mmc_omap_host *host = mmc_priv(mmc);
+
+       return sprintf(buf, "%s\n", mmc_omap_cover_is_closed(host) ? "closed" :
+                      "open");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
+static ssize_t
+mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
+                       char *buf)
+{
+       struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
+       struct mmc_omap_host *host = mmc_priv(mmc);
+       struct omap_mmc_slot_data slot = host->pdata->slots[host->slot_id];
+
+       return sprintf(buf, "slot:%s\n", slot.name);
+}
+
+static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
+
+/*
+ * Configure the response type and send the cmd.
+ */
+static void
+mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
+       struct mmc_data *data)
+{
+       int cmdreg = 0, resptype = 0, cmdtype = 0;
+
+       dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
+               mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
+       host->cmd = cmd;
+
+       /*
+        * Clear status bits and enable interrupts
+        */
+       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136)
+                       resptype = 1;
+               else
+                       resptype = 2;
+       }
+
+       /*
+        * Unlike OMAP1 controller, the cmdtype does not seem to be based on
+        * ac, bc, adtc, bcr. Only CMD12 needs a val of 0x3, rest 0x0.
+        */
+       if (cmd->opcode == 12)
+               cmdtype = 0x3;
+
+       cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
+
+       if (data) {
+               cmdreg |= DP_SELECT | MSBS | BCE;
+               if (data->flags & MMC_DATA_READ)
+                       cmdreg |= DDIR;
+               else
+                       cmdreg &= ~(DDIR);
+       }
+
+       if (host->use_dma)
+               cmdreg |= DMA_EN;
+
+       OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
+       OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
+}
+
+/*
+ * Notify the transfer complete to MMC core
+ */
+static void
+mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
+{
+       host->data = NULL;
+
+       if (host->use_dma && host->dma_ch != -1)
+               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+                       host->dma_dir);
+
+       host->datadir = OMAP_MMC_DATADIR_NONE;
+
+       if (!data->error)
+               data->bytes_xfered += data->blocks * (data->blksz);
+       else
+               data->bytes_xfered = 0;
+
+       if (!data->stop) {
+               host->mrq = NULL;
+               mmc_request_done(host->mmc, data->mrq);
+               return;
+       }
+       mmc_omap_start_command(host, data->stop, NULL);
+}
+
+/*
+ * Notify the core about command completion
+ */
+static void
+mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
+{
+       host->cmd = NULL;
+
+       if (cmd->flags & MMC_RSP_PRESENT) {
+               if (cmd->flags & MMC_RSP_136) {
+                       /* response type 2 */
+                       cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
+                       cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
+                       cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
+                       cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
+               } else {
+                       /* response types 1, 1b, 3, 4, 5, 6 */
+                       cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
+               }
+       }
+       if (host->data == NULL || cmd->error) {
+               host->mrq = NULL;
+               mmc_request_done(host->mmc, cmd->mrq);
+       }
+}
+
+/*
+ * DMA clean up for command errors
+ */
+static void mmc_dma_cleanup(struct mmc_omap_host *host)
+{
+       host->data->error = -ETIMEDOUT;
+
+       if (host->use_dma && host->dma_ch != -1) {
+               dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
+                       host->dma_dir);
+               omap_free_dma(host->dma_ch);
+               host->dma_ch = -1;
+               up(&host->sem);
+       }
+       host->data = NULL;
+       host->datadir = OMAP_MMC_DATADIR_NONE;
+}
+
+/*
+ * Readable error output
+ */
+#ifdef CONFIG_MMC_DEBUG
+static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status)
+{
+       /* --- means reserved bit without definition at documentation */
+       static const char *mmc_omap_status_bits[] = {
+               "CC", "TC", "BGE", "---", "BWR", "BRR", "---", "---", "CIRQ",
+               "OBI", "---", "---", "---", "---", "---", "ERRI", "CTO", "CCRC",
+               "CEB", "CIE", "DTO", "DCRC", "DEB", "---", "ACE", "---",
+               "---", "---", "---", "CERR", "CERR", "BADA", "---", "---", "---"
+       };
+       int i;
+
+       dev_dbg(mmc_dev(host->mmc), "MMC IRQ 0x%x :", status);
+
+       for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
+               if (status & (1 << i))
+                       /*
+                        * KERN_* facility is not used here because this should
+                        * print a single line.
+                        */
+                       printk(" %s", mmc_omap_status_bits[i]);
+
+       printk("\n");
+
+}
+#endif  /* CONFIG_MMC_DEBUG */
+
+
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
+{
+       struct mmc_omap_host *host = dev_id;
+       struct mmc_data *data;
+       int end_cmd = 0, end_trans = 0, status;
+
+       if (host->cmd == NULL && host->data == NULL) {
+               OMAP_HSMMC_WRITE(host->base, STAT,
+                       OMAP_HSMMC_READ(host->base, STAT));
+               return IRQ_HANDLED;
+       }
+
+       data = host->data;
+       status = OMAP_HSMMC_READ(host->base, STAT);
+       dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
+
+       if (status & ERR) {
+#ifdef CONFIG_MMC_DEBUG
+               mmc_omap_report_irq(host, status);
+#endif
+               if ((status & CMD_TIMEOUT) ||
+                       (status & CMD_CRC)) {
+                       if (host->cmd) {
+                               if (status & CMD_TIMEOUT) {
+                                       OMAP_HSMMC_WRITE(host->base, SYSCTL,
+                                               OMAP_HSMMC_READ(host->base,
+                                                               SYSCTL) | SRC);
+                                       while (OMAP_HSMMC_READ(host->base,
+                                                               SYSCTL) & SRC) ;
+                                       host->cmd->error = -ETIMEDOUT;
+                               } else {
+                                       host->cmd->error = -EILSEQ;
+                               }
+                               end_cmd = 1;
+                       }
+                       if (host->data)
+                               mmc_dma_cleanup(host);
+               }
+               if ((status & DATA_TIMEOUT) ||
+                       (status & DATA_CRC)) {
+                       if (host->data) {
+                               if (status & DATA_TIMEOUT)
+                                       mmc_dma_cleanup(host);
+                               else
+                                       host->data->error = -EILSEQ;
+                               end_trans = 1;
+                       }
+               }
+               if (status & CARD_ERR) {
+                       dev_dbg(mmc_dev(host->mmc),
+                               "Ignoring card err CMD%d\n", host->cmd->opcode);
+                       if (host->cmd)
+                               end_cmd = 1;
+                       if (host->data)
+                               end_trans = 1;
+               }
+       }
+
+       OMAP_HSMMC_WRITE(host->base, STAT, status);
+
+       if (end_cmd || (status & CC))
+               mmc_omap_cmd_done(host, host->cmd);
+       if (end_trans || (status & TC))
+               mmc_omap_xfer_done(host, data);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Switch MMC operating voltage
+ */
+static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
+{
+       u32 reg_val = 0;
+       int ret;
+
+       /* Disable the clocks */
+       clk_disable(host->fclk);
+       clk_disable(host->iclk);
+       clk_disable(host->dbclk);
+
+       /* Turn the power off */
+       ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+       if (ret != 0)
+               goto err;
+
+       /* Turn the power ON with given VDD 1.8 or 3.0v */
+       ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
+       if (ret != 0)
+               goto err;
+
+       clk_enable(host->fclk);
+       clk_enable(host->iclk);
+       clk_enable(host->dbclk);
+
+       OMAP_HSMMC_WRITE(host->base, HCTL,
+               OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
+       reg_val = OMAP_HSMMC_READ(host->base, HCTL);
+       /*
+        * If a MMC dual voltage card is detected, the set_ios fn calls
+        * this fn with VDD bit set for 1.8V. Upon card removal from the
+        * slot, mmc_omap_detect fn sets the VDD back to 3V.
+        *
+        * Only MMC1 supports 3.0V.  MMC2 will not function if SDVS30 is
+        * set in HCTL.
+        */
+       if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
+                               ((1 << vdd) == MMC_VDD_33_34)))
+               reg_val |= SDVS30;
+       if ((1 << vdd) == MMC_VDD_165_195)
+               reg_val |= SDVS18;
+
+       OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
+
+       OMAP_HSMMC_WRITE(host->base, HCTL,
+               OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+       return 0;
+err:
+       dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
+       return ret;
+}
+
+/*
+ * Work Item to notify the core about card insertion/removal
+ */
+static void mmc_omap_detect(struct work_struct *work)
+{
+       u16 vdd = 0;
+       struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
+                                               mmc_carddetect_work);
+
+       sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
+       if (host->carddetect) {
+               if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+                       /*
+                        * Set the VDD back to 3V when the card is removed
+                        * before the set_ios fn turns off the power.
+                        */
+                       vdd = fls(host->mmc->ocr_avail) - 1;
+                       if (omap_mmc_switch_opcond(host, vdd) != 0)
+                               host->mmc->ios.vdd = vdd;
+               }
+               mmc_detect_change(host->mmc, (HZ * 200) / 1000);
+       } else {
+               OMAP_HSMMC_WRITE(host->base, SYSCTL,
+                       OMAP_HSMMC_READ(host->base, SYSCTL) | SRD);
+               while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD) ;
+               mmc_detect_change(host->mmc, (HZ * 50) / 1000);
+       }
+}
+
+/*
+ * ISR for handling card insertion and removal
+ */
+static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id)
+{
+       struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
+
+       host->carddetect = mmc_slot(host).card_detect(irq);
+       schedule_work(&host->mmc_carddetect_work);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * DMA call back function
+ */
+static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct mmc_omap_host *host = data;
+
+       if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
+               dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
+
+       if (host->dma_ch < 0)
+               return;
+
+       omap_free_dma(host->dma_ch);
+       host->dma_ch = -1;
+       /*
+        * DMA Callback: run in interrupt context.
+        * mutex_unlock will through a kernel warning if used.
+        */
+       up(&host->sem);
+}
+
+/*
+ * Configure dma src and destination parameters
+ */
+static int mmc_omap_config_dma_param(int sync_dir, struct mmc_omap_host *host,
+                               struct mmc_data *data)
+{
+       if (sync_dir == 0) {
+               omap_set_dma_dest_params(host->dma_ch, 0,
+                       OMAP_DMA_AMODE_CONSTANT,
+                       (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
+               omap_set_dma_src_params(host->dma_ch, 0,
+                       OMAP_DMA_AMODE_POST_INC,
+                       sg_dma_address(&data->sg[0]), 0, 0);
+       } else {
+               omap_set_dma_src_params(host->dma_ch, 0,
+                       OMAP_DMA_AMODE_CONSTANT,
+                       (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
+               omap_set_dma_dest_params(host->dma_ch, 0,
+                       OMAP_DMA_AMODE_POST_INC,
+                       sg_dma_address(&data->sg[0]), 0, 0);
+       }
+       return 0;
+}
+/*
+ * Routine to configure and start DMA for the MMC card
+ */
+static int
+mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req)
+{
+       int sync_dev, sync_dir = 0;
+       int dma_ch = 0, ret = 0, err = 1;
+       struct mmc_data *data = req->data;
+
+       /*
+        * If for some reason the DMA transfer is still active,
+        * we wait for timeout period and free the dma
+        */
+       if (host->dma_ch != -1) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(100);
+               if (down_trylock(&host->sem)) {
+                       omap_free_dma(host->dma_ch);
+                       host->dma_ch = -1;
+                       up(&host->sem);
+                       return err;
+               }
+       } else {
+               if (down_trylock(&host->sem))
+                       return err;
+       }
+
+       if (!(data->flags & MMC_DATA_WRITE)) {
+               host->dma_dir = DMA_FROM_DEVICE;
+               if (host->id == OMAP_MMC1_DEVID)
+                       sync_dev = OMAP24XX_DMA_MMC1_RX;
+               else
+                       sync_dev = OMAP24XX_DMA_MMC2_RX;
+       } else {
+               host->dma_dir = DMA_TO_DEVICE;
+               if (host->id == OMAP_MMC1_DEVID)
+                       sync_dev = OMAP24XX_DMA_MMC1_TX;
+               else
+                       sync_dev = OMAP24XX_DMA_MMC2_TX;
+       }
+
+       ret = omap_request_dma(sync_dev, "MMC/SD", mmc_omap_dma_cb,
+                       host, &dma_ch);
+       if (ret != 0) {
+               dev_dbg(mmc_dev(host->mmc),
+                       "%s: omap_request_dma() failed with %d\n",
+                       mmc_hostname(host->mmc), ret);
+               return ret;
+       }
+
+       host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
+                       data->sg_len, host->dma_dir);
+       host->dma_ch = dma_ch;
+
+       if (!(data->flags & MMC_DATA_WRITE))
+               mmc_omap_config_dma_param(1, host, data);
+       else
+               mmc_omap_config_dma_param(0, host, data);
+
+       if ((data->blksz % 4) == 0)
+               omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
+                       (data->blksz / 4), data->blocks, OMAP_DMA_SYNC_FRAME,
+                       sync_dev, sync_dir);
+       else
+               /* REVISIT: The MMC buffer increments only when MSB is written.
+                * Return error for blksz which is non multiple of four.
+                */
+               return -EINVAL;
+
+       omap_start_dma(dma_ch);
+       return 0;
+}
+
+/*
+ * Configure block length for MMC/SD cards and initiate the transfer.
+ */
+static int
+mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
+{
+       int ret;
+       host->data = req->data;
+
+       if (req->data == NULL) {
+               host->datadir = OMAP_MMC_DATADIR_NONE;
+               OMAP_HSMMC_WRITE(host->base, BLK, 0);
+               return 0;
+       }
+
+       OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
+                                       | (req->data->blocks << 16));
+
+       host->datadir = (req->data->flags & MMC_DATA_WRITE) ?
+                       OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ;
+
+       if (host->use_dma) {
+               ret = mmc_omap_start_dma_transfer(host, req);
+               if (ret != 0) {
+                       dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Request function. for read/write operation
+ */
+static void omap_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct mmc_omap_host *host = mmc_priv(mmc);
+
+       WARN_ON(host->mrq != NULL);
+       host->mrq = req;
+       mmc_omap_prepare_data(host, req);
+       mmc_omap_start_command(host, req->cmd, req->data);
+}
+
+
+/* Routine to configure clock values. Exposed API to core */
+static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct mmc_omap_host *host = mmc_priv(mmc);
+       u16 dsor = 0;
+       unsigned long regval;
+       unsigned long timeout;
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+               break;
+       case MMC_POWER_UP:
+               mmc_slot(host).set_power(host->dev, host->slot_id, 1, ios->vdd);
+               break;
+       }
+
+       switch (mmc->ios.bus_width) {
+       case MMC_BUS_WIDTH_4:
+               OMAP_HSMMC_WRITE(host->base, HCTL,
+                       OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
+               break;
+       case MMC_BUS_WIDTH_1:
+               OMAP_HSMMC_WRITE(host->base, HCTL,
+                       OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
+               break;
+       }
+
+       if (host->id == OMAP_MMC1_DEVID) {
+               /* Only MMC1 can operate at 3V/1.8V */
+               if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
+                       (ios->vdd == DUAL_VOLT_OCR_BIT)) {
+                               /*
+                                * The mmc_select_voltage fn of the core does
+                                * not seem to set the power_mode to
+                                * MMC_POWER_UP upon recalculating the voltage.
+                                * vdd 1.8v.
+                                */
+                               if (omap_mmc_switch_opcond(host, ios->vdd) != 0)
+                                       dev_dbg(mmc_dev(host->mmc),
+                                               "Switch operation failed\n");
+               }
+       }
+
+       if (ios->clock) {
+               dsor = OMAP_MMC_MASTER_CLOCK / ios->clock;
+               if (dsor < 1)
+                       dsor = 1;
+
+               if (OMAP_MMC_MASTER_CLOCK / dsor > ios->clock)
+                       dsor++;
+
+               if (dsor > 250)
+                       dsor = 250;
+       }
+       omap_mmc_stop_clock(host);
+       regval = OMAP_HSMMC_READ(host->base, SYSCTL);
+       regval = regval & ~(CLKD_MASK);
+       regval = regval | (dsor << 6) | (DTO << 16);
+       OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
+       OMAP_HSMMC_WRITE(host->base, SYSCTL,
+               OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
+
+       /* Wait till the ICS bit is set */
+       timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+       while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != 0x2
+               && time_before(jiffies, timeout))
+               msleep(1);
+
+       OMAP_HSMMC_WRITE(host->base, SYSCTL,
+               OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
+
+       if (ios->power_mode == MMC_POWER_ON)
+               send_init_stream(host);
+
+       if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               OMAP_HSMMC_WRITE(host->base, CON,
+                               OMAP_HSMMC_READ(host->base, CON) | OD);
+}
+/* NOTE: Read only switch not supported yet */
+static struct mmc_host_ops mmc_omap_ops = {
+       .request = omap_mmc_request,
+       .set_ios = omap_mmc_set_ios,
+};
+
+static int __init omap_mmc_probe(struct platform_device *pdev)
+{
+       struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
+       struct mmc_host *mmc;
+       struct mmc_omap_host *host = NULL;
+       struct resource *res;
+       int ret = 0, irq;
+       u32 hctl, capa;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "Platform Data is missing\n");
+               return -ENXIO;
+       }
+
+       if (pdata->nr_slots == 0) {
+               dev_err(&pdev->dev, "No Slots\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       if (res == NULL || irq < 0)
+               return -ENXIO;
+
+       res = request_mem_region(res->start, res->end - res->start + 1,
+                                                       pdev->name);
+       if (res == NULL)
+               return -EBUSY;
+
+       mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       host            = mmc_priv(mmc);
+       host->mmc       = mmc;
+       host->pdata     = pdata;
+       host->dev       = &pdev->dev;
+       host->use_dma   = 1;
+       host->dev->dma_mask = &pdata->dma_mask;
+       host->dma_ch    = -1;
+       host->irq       = irq;
+       host->id        = pdev->id;
+       host->slot_id   = 0;
+       host->mapbase   = res->start;
+       host->base      = ioremap(host->mapbase, SZ_4K);
+       mmc->ops        = &mmc_omap_ops;
+       mmc->f_min      = 400000;
+       mmc->f_max      = 52000000;
+
+       sema_init(&host->sem, 1);
+
+       host->iclk = clk_get(&pdev->dev, "mmchs_ick");
+       if (IS_ERR(host->iclk)) {
+               ret = PTR_ERR(host->iclk);
+               host->iclk = NULL;
+               goto err1;
+       }
+       host->fclk = clk_get(&pdev->dev, "mmchs_fck");
+       if (IS_ERR(host->fclk)) {
+               ret = PTR_ERR(host->fclk);
+               host->fclk = NULL;
+               clk_put(host->iclk);
+               goto err1;
+       }
+
+       if (clk_enable(host->fclk) != 0) {
+               clk_put(host->iclk);
+               clk_put(host->fclk);
+               goto err1;
+       }
+
+       if (clk_enable(host->iclk) != 0) {
+               clk_disable(host->fclk);
+               clk_put(host->iclk);
+               clk_put(host->fclk);
+               goto err1;
+       }
+
+       host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
+       /*
+        * MMC can still work without debounce clock.
+        */
+       if (IS_ERR(host->dbclk))
+               dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock\n");
+       else
+               if (clk_enable(host->dbclk) != 0)
+                       dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
+                                                       " clk failed\n");
+               else
+                       host->dbclk_enabled = 1;
+
+#ifdef CONFIG_MMC_BLOCK_BOUNCE
+       mmc->max_phys_segs = 1;
+       mmc->max_hw_segs = 1;
+#endif
+       mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
+       mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       mmc->ocr_avail = mmc_slot(host).ocr_mask;
+       mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+
+       if (pdata->slots[host->slot_id].wire4)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+       /* Only MMC1 supports 3.0V */
+       if (host->id == OMAP_MMC1_DEVID) {
+               hctl = SDVS30;
+               capa = VS30 | VS18;
+       } else {
+               hctl = SDVS18;
+               capa = VS18;
+       }
+
+       OMAP_HSMMC_WRITE(host->base, HCTL,
+                       OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+
+       OMAP_HSMMC_WRITE(host->base, CAPA,
+                       OMAP_HSMMC_READ(host->base, CAPA) | capa);
+
+       /* Set the controller to AUTO IDLE mode */
+       OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
+                       OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+
+       /* Set SD bus power bit */
+       OMAP_HSMMC_WRITE(host->base, HCTL,
+                       OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+       /* Request IRQ for MMC operations */
+       ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED,
+                       mmc_hostname(mmc), host);
+       if (ret) {
+               dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+               goto err_irq;
+       }
+
+       /* Request IRQ for card detect */
+       if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
+               ret = request_irq(mmc_slot(host).card_detect_irq,
+                                 omap_mmc_cd_handler,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                                         | IRQF_DISABLED,
+                                 mmc_hostname(mmc), host);
+               if (ret) {
+                       dev_dbg(mmc_dev(host->mmc),
+                               "Unable to grab MMC CD IRQ\n");
+                       goto err_irq_cd;
+               }
+       }
+
+       INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+       if (pdata->init != NULL) {
+               if (pdata->init(&pdev->dev) != 0) {
+                       dev_dbg(mmc_dev(host->mmc),
+                               "Unable to configure MMC IRQs\n");
+                       goto err_irq_cd_init;
+               }
+       }
+
+       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+
+       platform_set_drvdata(pdev, host);
+       mmc_add_host(mmc);
+
+       if (host->pdata->slots[host->slot_id].name != NULL) {
+               ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
+               if (ret < 0)
+                       goto err_slot_name;
+       }
+       if (mmc_slot(host).card_detect_irq && mmc_slot(host).card_detect &&
+                       host->pdata->slots[host->slot_id].get_cover_state) {
+               ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch);
+               if (ret < 0)
+                       goto err_cover_switch;
+       }
+
+       return 0;
+
+err_cover_switch:
+       device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
+err_slot_name:
+       mmc_remove_host(mmc);
+err_irq_cd_init:
+       free_irq(mmc_slot(host).card_detect_irq, host);
+err_irq_cd:
+       free_irq(host->irq, host);
+err_irq:
+       clk_disable(host->fclk);
+       clk_disable(host->iclk);
+       clk_put(host->fclk);
+       clk_put(host->iclk);
+       if (host->dbclk_enabled) {
+               clk_disable(host->dbclk);
+               clk_put(host->dbclk);
+       }
+
+err1:
+       iounmap(host->base);
+err:
+       dev_dbg(mmc_dev(host->mmc), "Probe Failed\n");
+       release_mem_region(res->start, res->end - res->start + 1);
+       if (host)
+               mmc_free_host(mmc);
+       return ret;
+}
+
+static int omap_mmc_remove(struct platform_device *pdev)
+{
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+       struct resource *res;
+       u16 vdd = 0;
+
+       if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+       /*
+        * Set the vdd back to 3V,
+        * applicable for dual volt support.
+        */
+               vdd = fls(host->mmc->ocr_avail) - 1;
+               if (omap_mmc_switch_opcond(host, vdd) != 0)
+                       host->mmc->ios.vdd = vdd;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res)
+               release_mem_region(res->start, res->end - res->start + 1);
+
+       platform_set_drvdata(pdev, NULL);
+       if (host) {
+               mmc_remove_host(host->mmc);
+               if (host->pdata->cleanup)
+                       host->pdata->cleanup(&pdev->dev);
+               free_irq(host->irq, host);
+               if (mmc_slot(host).card_detect_irq)
+                       free_irq(mmc_slot(host).card_detect_irq, host);
+               flush_scheduled_work();
+
+               clk_disable(host->fclk);
+               clk_disable(host->iclk);
+               clk_put(host->fclk);
+               clk_put(host->iclk);
+               if (host->dbclk_enabled) {
+                       clk_disable(host->dbclk);
+                       clk_put(host->dbclk);
+               }
+
+               mmc_free_host(host->mmc);
+               iounmap(host->base);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       int ret = 0;
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+       if (host && host->suspended)
+               return 0;
+
+       if (host) {
+               ret = mmc_suspend_host(host->mmc, state);
+               if (ret == 0) {
+                       host->suspended = 1;
+
+                       OMAP_HSMMC_WRITE(host->base, ISE, 0);
+                       OMAP_HSMMC_WRITE(host->base, IE, 0);
+
+                       if (host->pdata->suspend) {
+                               ret = host->pdata->suspend(&pdev->dev, host->slot_id);
+                               if (ret)
+                                       dev_dbg(mmc_dev(host->mmc),
+                                               "Unable to handle MMC board"
+                                               " level suspend\n");
+                       }
+
+                       if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+                               OMAP_HSMMC_WRITE(host->base, HCTL,
+                                       OMAP_HSMMC_READ(host->base, HCTL)
+                                       & SDVSCLR);
+                               OMAP_HSMMC_WRITE(host->base, HCTL,
+                                       OMAP_HSMMC_READ(host->base, HCTL)
+                                       | SDVS30);
+                               OMAP_HSMMC_WRITE(host->base, HCTL,
+                                       OMAP_HSMMC_READ(host->base, HCTL)
+                                       | SDBP);
+                       }
+
+                       clk_disable(host->fclk);
+                       clk_disable(host->iclk);
+                       clk_disable(host->dbclk);
+               }
+
+       }
+       return ret;
+}
+
+/* Routine to resume the MMC device */
+static int omap_mmc_resume(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct mmc_omap_host *host = platform_get_drvdata(pdev);
+
+       if (host && !host->suspended)
+               return 0;
+
+       if (host) {
+
+               ret = clk_enable(host->fclk);
+               if (ret)
+                       goto clk_en_err;
+
+               ret = clk_enable(host->iclk);
+               if (ret) {
+                       clk_disable(host->fclk);
+                       clk_put(host->fclk);
+                       goto clk_en_err;
+               }
+
+               if (clk_enable(host->dbclk) != 0)
+                       dev_dbg(mmc_dev(host->mmc),
+                                       "Enabling debounce clk failed\n");
+
+               if (host->pdata->resume) {
+                       ret = host->pdata->resume(&pdev->dev, host->slot_id);
+                       if (ret)
+                               dev_dbg(mmc_dev(host->mmc),
+                                       "Unmask interrupt failed\n");
+               }
+
+               /* Notify the core to resume the host */
+               ret = mmc_resume_host(host->mmc);
+               if (ret == 0)
+                       host->suspended = 0;
+       }
+
+       return ret;
+
+clk_en_err:
+       dev_dbg(mmc_dev(host->mmc),
+               "Failed to enable MMC clocks during resume\n");
+       return ret;
+}
+
+#else
+#define omap_mmc_suspend       NULL
+#define omap_mmc_resume                NULL
+#endif
+
+static struct platform_driver omap_mmc_driver = {
+       .probe          = omap_mmc_probe,
+       .remove         = omap_mmc_remove,
+       .suspend        = omap_mmc_suspend,
+       .resume         = omap_mmc_resume,
+       .driver         = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init omap_mmc_init(void)
+{
+       /* Register the MMC driver */
+       return platform_driver_register(&omap_mmc_driver);
+}
+
+static void __exit omap_mmc_cleanup(void)
+{
+       /* Unregister MMC driver */
+       platform_driver_unregister(&omap_mmc_driver);
+}
+
+module_init(omap_mmc_init);
+module_exit(omap_mmc_cleanup);
+
+MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Texas Instruments Inc");
index 71bc07f149b7910f964a5bc9b4c678a149cfbdf9..69f471b94b1eeec4f6a4aec7ba25a865826005d7 100644 (file)
@@ -349,7 +349,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
  *
  * This function needs to be visible for bootloaders.
  */
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
 {
        cmdline = s;
        return 1;
index 0a60ebbc217591af7c00511ad3096f8d2fa9656d..2cbd75e1b2df666f9d5685e9c90f50ee012f7574 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/hardware.h>
+#include <mach/hardware.h>
 #include <asm/io.h>
 
 
index 05f276af15da39043f0c5f7ee893e70a7f9df826..73bc2771aa905970bdff1d5254d55e7404cca0d8 100644 (file)
@@ -142,11 +142,12 @@ out_free_info:
 static int __exit omapflash_remove(struct platform_device *pdev)
 {
        struct omapflash_info *info = platform_get_drvdata(pdev);
+       struct flash_platform_data *pdata = pdev->dev.platform_data;
 
        platform_set_drvdata(pdev, NULL);
 
        if (info) {
-               if (info->parts) {
+               if (info->parts || (pdata && pdata->parts)) {
                        del_mtd_partitions(info->mtd);
                        kfree(info->parts);
                } else
index 41f361c49b32b73344b62f0838eb35647328dceb..ed1a33152bfd6482e8b489af2e2a7bcbd9eac3a0 100644 (file)
@@ -68,6 +68,25 @@ config MTD_NAND_AMS_DELTA
        help
          Support for NAND flash on Amstrad E3 (Delta).
 
+config MTD_NAND_OMAP2
+       tristate "NAND Flash device on OMAP2 and OMAP3"
+       depends on ARM && MTD_NAND && (ARCH_OMAP2 || ARCH_OMAP3)
+       help
+          Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
+
+config MTD_NAND_OMAP
+       tristate "NAND Flash device on OMAP H3/H2/P2 boards"
+       depends on ARM && ARCH_OMAP1 && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_PERSEUS2)
+       help
+         Support for NAND flash on Texas Instruments H3/H2/P2 platforms.
+
+config MTD_NAND_OMAP_HW
+       bool "OMAP HW NAND Flash controller support"
+        depends on ARM && ARCH_OMAP16XX && MTD_NAND
+
+       help
+         Driver for TI OMAP16xx hardware NAND flash controller.
+
 config MTD_NAND_TOTO
        tristate "NAND Flash device on TOTO board"
        depends on ARCH_OMAP && BROKEN
index b786c5da82da227fe388bf468c6dc370caee49ea..ba42584b0abc885673d66fbbb5e98cb771a61d95 100644 (file)
@@ -24,6 +24,9 @@ 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_ATMEL)           += atmel_nand.o
+obj-$(CONFIG_MTD_NAND_OMAP)            += omap-nand-flash.o
+obj-$(CONFIG_MTD_NAND_OMAP2)           += omap2.o
+obj-$(CONFIG_MTD_NAND_OMAP_HW)         += omap-hw.o
 obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
 obj-$(CONFIG_MTD_NAND_PXA3xx)          += pxa3xx_nand.o
index 26d42987971fc9480520454fd2944e23c5f47641..782994ead0e83e1a123d011ac867ee3c9ea08c17 100644 (file)
@@ -145,7 +145,7 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
 
 static int ams_delta_nand_ready(struct mtd_info *mtd)
 {
-       return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
+       return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
 }
 
 /*
@@ -185,7 +185,7 @@ static int __init ams_delta_init(void)
        this->read_buf = ams_delta_read_buf;
        this->verify_buf = ams_delta_verify_buf;
        this->cmd_ctrl = ams_delta_hwcontrol;
-       if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
+       if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
                this->dev_ready = ams_delta_nand_ready;
        } else {
                this->dev_ready = NULL;
diff --git a/drivers/mtd/nand/omap-hw.c b/drivers/mtd/nand/omap-hw.c
new file mode 100644 (file)
index 0000000..7eb9894
--- /dev/null
@@ -0,0 +1,859 @@
+/*
+ *  drivers/mtd/nand/omap-hw.c
+ *
+ *  This is the MTD driver for OMAP1710 internal HW NAND controller.
+ *
+ *  Copyright (C) 2004-2006 Nokia Corporation
+ *
+ *  Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and
+ *          Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+#include <mach/board.h>
+#include <mach/dma.h>
+
+#define NAND_BASE              0xfffbcc00
+#define NND_REVISION           0x00
+#define NND_ACCESS             0x04
+#define NND_ADDR_SRC           0x08
+#define NND_CTRL               0x10
+#define NND_MASK               0x14
+#define NND_STATUS             0x18
+#define NND_READY              0x1c
+#define NND_COMMAND            0x20
+#define NND_COMMAND_SEC                0x24
+#define NND_ECC_SELECT         0x28
+#define NND_ECC_START          0x2c
+#define NND_ECC_9              0x4c
+#define NND_RESET              0x50
+#define NND_FIFO               0x54
+#define NND_FIFOCTRL           0x58
+#define NND_PSC_CLK            0x5c
+#define NND_SYSTEST            0x60
+#define NND_SYSCFG             0x64
+#define NND_SYSSTATUS          0x68
+#define NND_FIFOTEST1          0x6c
+#define NND_FIFOTEST2          0x70
+#define NND_FIFOTEST3          0x74
+#define NND_FIFOTEST4          0x78
+#define NND_PSC1_CLK           0x8c
+#define NND_PSC2_CLK           0x90
+
+
+#define NND_CMD_READ1_LOWER    0x00
+#define NND_CMD_WRITE1_LOWER   0x00
+#define NND_CMD_READ1_UPPER    0x01
+#define NND_CMD_WRITE1_UPPER   0x01
+#define NND_CMD_PROGRAM_END    0x10
+#define NND_CMD_READ2_SPARE    0x50
+#define NND_CMD_WRITE2_SPARE   0x50
+#define NND_CMD_ERASE          0x60
+#define NND_CMD_STATUS         0x70
+#define NND_CMD_PROGRAM                0x80
+#define NND_CMD_READ_ID                0x90
+#define NND_CMD_ERASE_END      0xD0
+#define NND_CMD_RESET          0xFF
+
+
+#define NAND_Ecc_P1e           (1 << 0)
+#define NAND_Ecc_P2e           (1 << 1)
+#define NAND_Ecc_P4e           (1 << 2)
+#define NAND_Ecc_P8e           (1 << 3)
+#define NAND_Ecc_P16e          (1 << 4)
+#define NAND_Ecc_P32e          (1 << 5)
+#define NAND_Ecc_P64e          (1 << 6)
+#define NAND_Ecc_P128e         (1 << 7)
+#define NAND_Ecc_P256e         (1 << 8)
+#define NAND_Ecc_P512e         (1 << 9)
+#define NAND_Ecc_P1024e                (1 << 10)
+#define NAND_Ecc_P2048e                (1 << 11)
+
+#define NAND_Ecc_P1o           (1 << 16)
+#define NAND_Ecc_P2o           (1 << 17)
+#define NAND_Ecc_P4o           (1 << 18)
+#define NAND_Ecc_P8o           (1 << 19)
+#define NAND_Ecc_P16o          (1 << 20)
+#define NAND_Ecc_P32o          (1 << 21)
+#define NAND_Ecc_P64o          (1 << 22)
+#define NAND_Ecc_P128o         (1 << 23)
+#define NAND_Ecc_P256o         (1 << 24)
+#define NAND_Ecc_P512o         (1 << 25)
+#define NAND_Ecc_P1024o                (1 << 26)
+#define NAND_Ecc_P2048o                (1 << 27)
+
+#define TF(value)      (value ? 1 : 0)
+
+#define P2048e(a)      (TF(a & NAND_Ecc_P2048e)        << 0 )
+#define P2048o(a)      (TF(a & NAND_Ecc_P2048o)        << 1 )
+#define P1e(a)         (TF(a & NAND_Ecc_P1e)           << 2 )
+#define P1o(a)         (TF(a & NAND_Ecc_P1o)           << 3 )
+#define P2e(a)         (TF(a & NAND_Ecc_P2e)           << 4 )
+#define P2o(a)         (TF(a & NAND_Ecc_P2o)           << 5 )
+#define P4e(a)         (TF(a & NAND_Ecc_P4e)           << 6 )
+#define P4o(a)         (TF(a & NAND_Ecc_P4o)           << 7 )
+
+#define P8e(a)         (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o(a)         (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e(a)                (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o(a)                (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P32e(a)                (TF(a & NAND_Ecc_P32e)          << 4 )
+#define P32o(a)                (TF(a & NAND_Ecc_P32o)          << 5 )
+#define P64e(a)                (TF(a & NAND_Ecc_P64e)          << 6 )
+#define P64o(a)                (TF(a & NAND_Ecc_P64o)          << 7 )
+
+#define P128e(a)       (TF(a & NAND_Ecc_P128e)         << 0 )
+#define P128o(a)       (TF(a & NAND_Ecc_P128o)         << 1 )
+#define P256e(a)       (TF(a & NAND_Ecc_P256e)         << 2 )
+#define P256o(a)       (TF(a & NAND_Ecc_P256o)         << 3 )
+#define P512e(a)       (TF(a & NAND_Ecc_P512e)         << 4 )
+#define P512o(a)       (TF(a & NAND_Ecc_P512o)         << 5 )
+#define P1024e(a)      (TF(a & NAND_Ecc_P1024e)        << 6 )
+#define P1024o(a)      (TF(a & NAND_Ecc_P1024o)        << 7 )
+
+#define P8e_s(a)       (TF(a & NAND_Ecc_P8e)           << 0 )
+#define P8o_s(a)       (TF(a & NAND_Ecc_P8o)           << 1 )
+#define P16e_s(a)      (TF(a & NAND_Ecc_P16e)          << 2 )
+#define P16o_s(a)      (TF(a & NAND_Ecc_P16o)          << 3 )
+#define P1e_s(a)       (TF(a & NAND_Ecc_P1e)           << 4 )
+#define P1o_s(a)       (TF(a & NAND_Ecc_P1o)           << 5 )
+#define P2e_s(a)       (TF(a & NAND_Ecc_P2e)           << 6 )
+#define P2o_s(a)       (TF(a & NAND_Ecc_P2o)           << 7 )
+
+#define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0 )
+#define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1 )
+
+extern struct nand_oobinfo jffs2_oobinfo;
+
+/*
+ * MTD structure for OMAP board
+ */
+static struct mtd_info *omap_mtd;
+static struct clk *omap_nand_clk;
+static int omap_nand_dma_ch;
+static struct completion omap_nand_dma_comp;
+static unsigned long omap_nand_base = OMAP1_IO_ADDRESS(NAND_BASE);
+
+static inline u32 nand_read_reg(int idx)
+{
+       return __raw_readl(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg(int idx, u32 val)
+{
+       __raw_writel(val, omap_nand_base + idx);
+}
+
+static inline u8 nand_read_reg8(int idx)
+{
+       return __raw_readb(omap_nand_base + idx);
+}
+
+static inline void nand_write_reg8(int idx, u8 val)
+{
+       __raw_writeb(val, omap_nand_base + idx);
+}
+
+static void omap_nand_select_chip(struct mtd_info *mtd, int chip)
+{
+       u32 l;
+
+       switch(chip) {
+       case -1:
+               l = nand_read_reg(NND_CTRL);
+               l |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 14);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       case 0:
+               /* Also CS1, CS2, CS4 would be available */
+               l = nand_read_reg(NND_CTRL);
+               l &= ~(1 << 8);
+               nand_write_reg(NND_CTRL, l);
+               break;
+       default:
+               BUG();
+       }
+}
+
+static void nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+       complete((struct completion *) data);
+}
+
+static void omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+                                         unsigned int u32_count, int is_write)
+{
+       const int block_size = 16;
+       unsigned int block_count, len;
+       int dma_ch;
+       unsigned long fifo_reg, timeout, jiffies_before, jiffies_spent;
+       static unsigned long max_jiffies = 0;
+
+       dma_ch = omap_nand_dma_ch;
+       block_count = u32_count * 4 / block_size;
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | block_count);
+       fifo_reg = NAND_BASE + NND_FIFO;
+       if (is_write) {
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                        OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                        0, 0);
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                       OMAP_DMA_AMODE_POST_INC,
+                                       virt_to_phys(addr),
+                                       0, 0);
+//             omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
+               /* Set POSTWRITE bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 16));
+       } else {
+               omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB,
+                                       OMAP_DMA_AMODE_CONSTANT, fifo_reg,
+                                       0, 0);
+               omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF,
+                                        OMAP_DMA_AMODE_POST_INC,
+                                        virt_to_phys(addr),
+                                        0, 0);
+//             omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_8);
+               /* Set PREFETCH bit */
+               nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       }
+       omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, block_size / 4,
+                                    block_count, OMAP_DMA_SYNC_FRAME,
+                                    0, 0);
+       init_completion(&omap_nand_dma_comp);
+
+       len = u32_count << 2;
+       dma_cache_maint(addr, len, DMA_TO_DEVICE);
+       omap_start_dma(dma_ch);
+       jiffies_before = jiffies;
+       timeout = wait_for_completion_timeout(&omap_nand_dma_comp,
+                                             msecs_to_jiffies(1000));
+       jiffies_spent = (unsigned long)((long)jiffies - (long)jiffies_before);
+       if (jiffies_spent > max_jiffies)
+               max_jiffies = jiffies_spent;
+
+       if (timeout == 0) {
+               printk(KERN_WARNING "omap-hw-nand: DMA timeout after %u ms, max. seen latency %u ms\n",
+                      jiffies_to_msecs(jiffies_spent),
+                      jiffies_to_msecs(max_jiffies));
+       }
+       if (!is_write)
+               dma_cache_maint(addr, len, DMA_FROM_DEVICE);
+
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~((1 << 16) | (1 << 17)));
+}
+
+static void fifo_read(u32 *out, unsigned int len)
+{
+       const int block_size = 16;
+       unsigned long status_reg, fifo_reg;
+       int c;
+
+       status_reg = omap_nand_base + NND_STATUS;
+       fifo_reg = omap_nand_base + NND_FIFO;
+       len = len * 4 / block_size;
+       nand_write_reg(NND_FIFOCTRL, (block_size << 24) | len);
+       nand_write_reg(NND_STATUS, 0x0f);
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17));
+       c = block_size / 4;
+       while (len--) {
+               int i;
+
+               while ((__raw_readl(status_reg) & (1 << 2)) == 0);
+               __raw_writel(0x0f, status_reg);
+               for (i = 0; i < c; i++) {
+                       u32 l = __raw_readl(fifo_reg);
+                       *out++ = l;
+               }
+       }
+       nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~(1 << 17));
+       nand_write_reg(NND_STATUS, 0x0f);
+}
+
+static void omap_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       unsigned long access_reg;
+
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               int u32_count = len >> 2;
+               u32 *dest = (u32 *) buf;
+               /* If the transfer is big enough and the length divisible by
+                * 16, we try to use DMA transfer, or FIFO copy in case of
+                * DMA failure (e.g. all channels busy) */
+               if (u32_count > 64 && (u32_count & 3) == 0) {
+                       if (omap_nand_dma_ch >= 0) {
+                               omap_nand_dma_transfer(mtd, buf, u32_count, 0);
+                               return;
+                       }
+                       /* In case of an error, fallback to FIFO copy */
+                       fifo_read((u32 *) buf, u32_count);
+                       return;
+               }
+               access_reg = omap_nand_base + NND_ACCESS;
+               /* Small buffers we just read directly */
+               while (u32_count--)
+                       *dest++ = __raw_readl(access_reg);
+       } else {
+               /* If we're not word-aligned, we use byte copy */
+               access_reg = omap_nand_base + NND_ACCESS;
+               while (len--)
+                       *buf++ = __raw_readb(access_reg);
+       }
+}
+
+static void omap_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *src = (const u32 *) buf;
+
+               len >>= 2;
+#if 0
+               /* If the transfer is big enough and length divisible by 16,
+                * we try to use DMA transfer. */
+               if (len > 256 / 4 && (len & 3) == 0) {
+                       if (omap_nand_dma_transfer(mtd, (void *) buf, len, 1) == 0)
+                               return;
+                       /* In case of an error, fallback to CPU copy */
+               }
+#endif
+               while (len--)
+                       nand_write_reg(NND_ACCESS, *src++);
+       } else {
+               while (len--)
+                       nand_write_reg8(NND_ACCESS, *buf++);
+       }
+}
+
+static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) {
+               const u32 *dest = (const u32 *) buf;
+               len >>= 2;
+               while (len--)
+                       if (*dest++ != nand_read_reg(NND_ACCESS))
+                               return -EFAULT;
+       } else {
+               while (len--)
+                       if (*buf++ != nand_read_reg8(NND_ACCESS))
+                               return -EFAULT;
+       }
+       return 0;
+}
+
+static u_char omap_nand_read_byte(struct mtd_info *mtd)
+{
+       return nand_read_reg8(NND_ACCESS);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       u32 l;
+
+       l = nand_read_reg(NND_READY);
+       return l & 0x01;
+}
+
+static int nand_write_command(u8 cmd, u32 addr, int addr_valid)
+{
+       if (addr_valid) {
+               nand_write_reg(NND_ADDR_SRC, addr);
+               nand_write_reg8(NND_COMMAND, cmd);
+       } else {
+               nand_write_reg(NND_ADDR_SRC, 0);
+               nand_write_reg8(NND_COMMAND_SEC, cmd);
+       }
+       while (!omap_nand_dev_ready(NULL));
+       return 0;
+}
+
+/*
+ * Send command to NAND device
+ */
+static void omap_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       /*
+        * Write out the command to the device.
+        */
+       if (command == NAND_CMD_SEQIN) {
+               int readcmd;
+
+               if (column >= mtd->writesize) {
+                       /* OOB area */
+                       column -= mtd->writesize;
+                       readcmd = NAND_CMD_READOOB;
+               } else if (column < 256) {
+                       /* First 256 bytes --> READ0 */
+                       readcmd = NAND_CMD_READ0;
+               } else {
+                       column -= 256;
+                       readcmd = NAND_CMD_READ1;
+               }
+               nand_write_command(readcmd, 0, 0);
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, ((page_addr & 0xFFFFFF00) << 1) | (page_addr & 0XFF), 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << this->page_shift) | column, 1);
+       }
+}
+
+static void omap_nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr)
+{
+       struct nand_chip *this = mtd->priv;
+
+       if (command == NAND_CMD_READOOB) {
+               column += mtd->writesize;
+               command = NAND_CMD_READ0;
+       }
+       switch (command) {
+       case NAND_CMD_RESET:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_ERASE2:           
+               nand_write_command(command, 0, 0);
+               break;
+       case NAND_CMD_ERASE1:
+               nand_write_command(command, page_addr << this->page_shift >> 11, 1);
+               break;
+       default:
+               nand_write_command(command, (page_addr << 16) | column, 1);
+       }
+       if (command == NAND_CMD_READ0)
+               nand_write_command(NAND_CMD_READSTART, 0, 0);
+}
+
+/*
+ * Generate non-inverted ECC bytes.
+ *
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page.
+ *
+ * Reading an erased page will produce an ECC mismatch between
+ * generated and read ECC bytes that has to be dealt with separately.
+ */
+static int omap_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+       u32 l;
+       int reg;
+       int n;
+       struct nand_chip *this = mtd->priv;
+
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               n = 4;
+       else
+               n = 1;
+       reg = NND_ECC_START;
+       while (n--) {
+               l = nand_read_reg(reg);
+               *ecc_code++ = l;          // P128e, ..., P1e
+               *ecc_code++ = l >> 16;    // P128o, ..., P1o
+               // P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e
+               *ecc_code++ = ((l >> 8) & 0x0f) | ((l >> 20) & 0xf0);
+               reg += 4;
+       }
+       return 0;
+}
+
+/*
+ * This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+       u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+       ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp) );
+       ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+       ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/*
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer
+ */
+static int omap_nand_compare_ecc(u8 *ecc_data1,   /* read from NAND memory */
+                                u8 *ecc_data2,   /* read from register */
+                                u8 *page_data)
+{
+       uint   i;
+       u8     tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+       u8     comp0_bit[8], comp1_bit[8], comp2_bit[8];
+       u8     ecc_bit[24];
+       u8     ecc_sum = 0;
+       u8     find_bit = 0;
+       uint   find_byte = 0;
+       int    isEccFF;
+
+       isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+       gen_true_ecc(ecc_data1);
+       gen_true_ecc(ecc_data2);
+
+       for (i = 0; i <= 2; i++) {
+               *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+               *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp0_bit[i]      = *ecc_data1 % 2;
+               *ecc_data1       = *ecc_data1 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp1_bit[i]      = *(ecc_data1 + 1) % 2;
+               *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp2_bit[i]      = *(ecc_data1 + 2) % 2;
+               *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp0_bit[i]     = *ecc_data2 % 2;
+               *ecc_data2       = *ecc_data2 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+               *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+               *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+       }
+
+       for (i = 0; i< 6; i++ )
+               ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+       ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+       ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+       for (i = 0; i < 24; i++)
+               ecc_sum += ecc_bit[i];
+
+       switch (ecc_sum) {
+       case 0:
+               /* Not reached because this function is not called if
+                  ECC values are equal */
+               return 0;
+
+       case 1:
+               /* Uncorrectable error */
+               DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+               return -1;
+
+       case 12:
+               /* Correctable error */
+               find_byte = (ecc_bit[23] << 8) + 
+                           (ecc_bit[21] << 7) + 
+                           (ecc_bit[19] << 6) +
+                           (ecc_bit[17] << 5) +
+                           (ecc_bit[15] << 4) +
+                           (ecc_bit[13] << 3) +
+                           (ecc_bit[11] << 2) +
+                           (ecc_bit[9]  << 1) +
+                           ecc_bit[7];
+
+               find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+               DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
+
+               page_data[find_byte] ^= (1 << find_bit);
+
+               return 0;
+       default:
+               if (isEccFF) {
+                       if (ecc_data2[0] == 0 && ecc_data2[1] == 0 && ecc_data2[2] == 0)
+                               return 0;
+               } 
+               DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+               return -1;
+       }
+}
+
+static int omap_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+       struct nand_chip *this;
+       int block_count = 0, i, r;
+
+       this = mtd->priv;
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((this->ecc.mode == NAND_ECC_HW) && (this->ecc.size  == 2048))
+               block_count = 4;
+       else
+               block_count = 1;
+       for (i = 0; i < block_count; i++) {
+               if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+                       r = omap_nand_compare_ecc(read_ecc, calc_ecc, dat);
+                       if (r < 0)
+                               return r;
+               }
+               read_ecc += 3;
+               calc_ecc += 3;
+               dat += 512;
+       }
+       return 0;
+}
+
+static void omap_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       nand_write_reg(NND_RESET, 0x01);
+}
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+
+extern int mtdpart_setup(char *);
+
+static int __init add_dynamic_parts(struct mtd_info *mtd)
+{
+       static const char *part_parsers[] = { "cmdlinepart", NULL };
+       struct mtd_partition *parts;
+       const struct omap_flash_part_str_config *cfg;
+       char *part_str = NULL;
+       size_t part_str_len;
+       int c;
+
+       cfg = omap_get_var_config(OMAP_TAG_FLASH_PART_STR, &part_str_len);
+       if (cfg != NULL) {
+               part_str = kmalloc(part_str_len + 1, GFP_KERNEL);
+               if (part_str == NULL)
+                       return -ENOMEM;
+               memcpy(part_str, cfg->part_table, part_str_len);
+               part_str[part_str_len] = '\0';
+               mtdpart_setup(part_str);
+       }
+       c = parse_mtd_partitions(omap_mtd, part_parsers, &parts, 0);
+       if (part_str != NULL) {
+               mtdpart_setup(NULL);
+               kfree(part_str);
+       }
+       if (c <= 0)
+               return -1;
+
+       add_mtd_partitions(mtd, parts, c);
+
+       return 0;
+}
+
+#else
+
+static inline int add_dynamic_parts(struct mtd_info *mtd)
+{
+       return -1;
+}
+
+#endif
+
+static inline int calc_psc(int ns, int cycle_ps)
+{
+       return (ns * 1000 + (cycle_ps - 1)) / cycle_ps;
+}
+
+static void set_psc_regs(int psc_ns, int psc1_ns, int psc2_ns)
+{
+       int psc[3], i;
+       unsigned long rate, ps;
+
+       rate = clk_get_rate(omap_nand_clk);
+       ps = 1000000000 / (rate / 1000);
+       psc[0] = calc_psc(psc_ns, ps);
+       psc[1] = calc_psc(psc1_ns, ps);
+       psc[2] = calc_psc(psc2_ns, ps);
+       for (i = 0; i < 3; i++) {
+               if (psc[i] < 2)
+                       psc[i] = 2;
+               else if (psc[i] > 256)
+                       psc[i] = 256;
+       }
+       nand_write_reg(NND_PSC_CLK, psc[0] - 1);
+       nand_write_reg(NND_PSC1_CLK, psc[1] - 1);
+       nand_write_reg(NND_PSC2_CLK, psc[2] - 1);
+       printk(KERN_INFO "omap-hw-nand: using PSC values %d, %d, %d\n", psc[0], psc[1], psc[2]);
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init omap_nand_init(void)
+{
+       struct nand_chip *this;
+       int err = 0;
+       u32 l;
+
+       omap_nand_clk = clk_get(NULL, "armper_ck");
+       BUG_ON(omap_nand_clk == NULL);
+       clk_enable(omap_nand_clk);
+
+       l = nand_read_reg(NND_REVISION);        
+       printk(KERN_INFO "omap-hw-nand: OMAP NAND Controller rev. %d.%d\n", l>>4, l & 0xf);
+
+       /* Reset the NAND Controller */
+       nand_write_reg(NND_SYSCFG, 0x02);
+       while ((nand_read_reg(NND_SYSSTATUS) & 0x01) == 0);
+
+       /* No Prefetch, no postwrite, write prot & enable pairs disabled,
+          addres counter set to send 4 byte addresses to flash,
+          A8 is set not to be sent to flash (erase addre needs formatting),
+          choose little endian, enable 512 byte ECC logic,        
+        */
+       nand_write_reg(NND_CTRL, 0xFF01);
+
+       /* Allocate memory for MTD device structure and private data */
+       omap_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+       if (!omap_mtd) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to allocate OMAP NAND MTD device structure.\n");
+               err = -ENOMEM;
+               goto free_clock;
+       }
+#if 1
+       err = omap_request_dma(OMAP_DMA_NAND, "NAND", nand_dma_cb,
+                              &omap_nand_dma_comp, &omap_nand_dma_ch);
+       if (err < 0) {
+               printk(KERN_WARNING "omap-hw-nand: Unable to reserve DMA channel\n");
+               omap_nand_dma_ch = -1;
+       }
+#else
+       omap_nand_dma_ch = -1;
+#endif
+       /* Get pointer to private data */
+       this = (struct nand_chip *) (&omap_mtd[1]);
+
+       /* Initialize structures */
+       memset((char *) omap_mtd, 0, sizeof(struct mtd_info));
+       memset((char *) this, 0, sizeof(struct nand_chip));
+
+       /* Link the private data with the MTD structure */
+       omap_mtd->priv = this;
+       omap_mtd->name = "omap-nand";
+
+       this->options = NAND_SKIP_BBTSCAN;
+
+       /* Used from chip select and nand_command() */
+       this->read_byte = omap_nand_read_byte;
+
+       this->select_chip   = omap_nand_select_chip;
+       this->dev_ready     = omap_nand_dev_ready;
+       this->chip_delay    = 0;
+       this->ecc.mode      = NAND_ECC_HW;
+       this->ecc.bytes     = 3;
+       this->ecc.size      = 512;
+       this->cmdfunc       = omap_nand_command;
+       this->write_buf     = omap_nand_write_buf;
+       this->read_buf      = omap_nand_read_buf;
+       this->verify_buf    = omap_nand_verify_buf;
+       this->ecc.calculate = omap_nand_calculate_ecc;
+       this->ecc.correct   = omap_nand_correct_data;
+       this->ecc.hwctl     = omap_nand_enable_hwecc;
+
+       nand_write_reg(NND_SYSCFG, 0x1); /* Enable auto idle */
+       nand_write_reg(NND_PSC_CLK, 10);
+       /* Scan to find existance of the device */
+       if (nand_scan(omap_mtd, 1)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       set_psc_regs(25, 15, 35);
+       if (this->page_shift == 11) {
+               this->cmdfunc = omap_nand_command_lp;
+               l = nand_read_reg(NND_CTRL);
+               l |= 1 << 4; /* Set the A8 bit in CTRL reg */
+               nand_write_reg(NND_CTRL, l);
+               this->ecc.mode = NAND_ECC_HW;
+               this->ecc.steps = 1;
+               this->ecc.size = 2048;
+               this->ecc.bytes = 12;
+               nand_write_reg(NND_ECC_SELECT, 6);
+       }
+
+       /* We have to do bbt scanning ourselves */
+       if (this->scan_bbt (omap_mtd)) {
+               err = -ENXIO;
+               goto out_mtd;
+       }
+
+       err = add_dynamic_parts(omap_mtd);
+       if (err < 0) {
+               printk(KERN_ERR "omap-hw-nand: no partitions defined\n");
+               err = -ENODEV;
+               nand_release(omap_mtd);
+               goto out_mtd;
+       }
+       /* init completed */
+       return 0;
+out_mtd:
+       if (omap_nand_dma_ch >= 0)
+               omap_free_dma(omap_nand_dma_ch);
+       kfree(omap_mtd);
+free_clock:
+       clk_put(omap_nand_clk);
+       return err;
+}
+
+module_init(omap_nand_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit omap_nand_cleanup (void)
+{
+       clk_disable(omap_nand_clk);
+       clk_put(omap_nand_clk);
+       nand_release(omap_mtd);
+       kfree(omap_mtd);
+}
+
+module_exit(omap_nand_cleanup);
+
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..6b8fb44
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * drivers/mtd/nand/omap-nand-flash.c
+ *
+ * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright (c) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <mach/tc.h>
+
+#include <mach/nand.h>
+
+#define        DRIVER_NAME     "omapnand"
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+struct omap_nand_info {
+       struct omap_nand_platform_data *pdata;
+       struct mtd_partition    *parts;
+       struct mtd_info         mtd;
+       struct nand_chip        nand;
+};
+
+/*
+ *     hardware specific access to control-lines
+ *     NOTE:  boards may use different bits for these!!
+ *
+ *     ctrl:
+ *     NAND_NCE: bit 0 - don't care
+ *     NAND_CLE: bit 1 -> bit 1  (0x0002)
+ *     NAND_ALE: bit 2 -> bit 2  (0x0004)
+ */
+
+static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+       unsigned long mask;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+       if (ctrl & NAND_ALE)
+               mask |= 0x04;
+       writeb(cmd, (unsigned long)chip->IO_ADDR_W | mask);
+}
+
+static int omap_nand_dev_ready(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd);
+
+       return info->pdata->dev_ready(info->pdata);
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+       struct omap_nand_info           *info;
+       struct omap_nand_platform_data  *pdata = pdev->dev.platform_data;
+       struct resource                 *res = pdev->resource;
+       unsigned long                   size = res->end - res->start + 1;
+       int                             err;
+
+       info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       if (!request_mem_region(res->start, size, pdev->dev.driver->name)) {
+               err = -EBUSY;
+               goto out_free_info;
+       }
+
+       info->nand.IO_ADDR_R = ioremap(res->start, size);
+       if (!info->nand.IO_ADDR_R) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+       info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+       info->nand.cmd_ctrl = omap_nand_hwcontrol;
+       info->nand.ecc.mode = NAND_ECC_SOFT;
+       info->nand.options = pdata->options;
+       if (pdata->dev_ready)
+               info->nand.dev_ready = omap_nand_dev_ready;
+       else
+               info->nand.chip_delay = 20;
+
+       info->mtd.name = pdev->dev.bus_id;
+       info->mtd.priv = &info->nand;
+
+       info->pdata = pdata;
+
+       /* DIP switches on H2 and some other boards change between 8 and 16 bit
+        * bus widths for flash.  Try the other width if the first try fails.
+        */
+       if (nand_scan(&info->mtd, 1)) {
+               info->nand.options ^= NAND_BUSWIDTH_16;
+               if (nand_scan(&info->mtd, 1)) {
+                       err = -ENXIO;
+                       goto out_iounmap;
+               }
+       }
+       info->mtd.owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(&info->mtd, info->parts, err);
+       else if (err < 0 && pdata->parts)
+               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               add_mtd_device(&info->mtd);
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+
+out_iounmap:
+       iounmap(info->nand.IO_ADDR_R);
+out_release_mem_region:
+       release_mem_region(res->start, size);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+       struct omap_nand_info *info = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       /* Release NAND device, its internal structures and partitions */
+       nand_release(&info->mtd);
+       iounmap(info->nand.IO_ADDR_R);
+       kfree(info);
+       return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+       .probe          = omap_nand_probe,
+       .remove         = omap_nand_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+       return platform_driver_register(&omap_nand_driver);
+}
+
+static void __exit omap_nand_exit(void)
+{
+       platform_driver_unregister(&omap_nand_driver);
+}
+
+module_init(omap_nand_init);
+module_exit(omap_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jian Zhang <jzhang@ti.com> (and others)");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
+
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
new file mode 100644 (file)
index 0000000..2ede116
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ * drivers/mtd/nand/omap2.c
+ *
+ * Copyright (c) 2004 Texas Instruments, Jian Zhang <jzhang@ti.com>
+ * Copyright (c) 2004 Micron Technology Inc.
+ * Copyright (c) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+
+#include <mach/gpmc.h>
+#include <mach/nand.h>
+
+#define GPMC_IRQ_STATUS                0x18
+#define GPMC_ECC_CONFIG                0x1F4
+#define GPMC_ECC_CONTROL       0x1F8
+#define GPMC_ECC_SIZE_CONFIG   0x1FC
+#define GPMC_ECC1_RESULT       0x200
+
+#define        DRIVER_NAME     "omap2-nand"
+#define        NAND_IO_SIZE    SZ_4K
+
+#define        NAND_WP_ON      1
+#define        NAND_WP_OFF     0
+#define NAND_WP_BIT    0x00000010
+#define WR_RD_PIN_MONITORING   0x00600000
+
+#define        GPMC_BUF_FULL   0x00000001
+#define        GPMC_BUF_EMPTY  0x00000000
+
+#define NAND_Ecc_P1e           (1 << 0)
+#define NAND_Ecc_P2e           (1 << 1)
+#define NAND_Ecc_P4e           (1 << 2)
+#define NAND_Ecc_P8e           (1 << 3)
+#define NAND_Ecc_P16e          (1 << 4)
+#define NAND_Ecc_P32e          (1 << 5)
+#define NAND_Ecc_P64e          (1 << 6)
+#define NAND_Ecc_P128e         (1 << 7)
+#define NAND_Ecc_P256e         (1 << 8)
+#define NAND_Ecc_P512e         (1 << 9)
+#define NAND_Ecc_P1024e                (1 << 10)
+#define NAND_Ecc_P2048e                (1 << 11)
+
+#define NAND_Ecc_P1o           (1 << 16)
+#define NAND_Ecc_P2o           (1 << 17)
+#define NAND_Ecc_P4o           (1 << 18)
+#define NAND_Ecc_P8o           (1 << 19)
+#define NAND_Ecc_P16o          (1 << 20)
+#define NAND_Ecc_P32o          (1 << 21)
+#define NAND_Ecc_P64o          (1 << 22)
+#define NAND_Ecc_P128o         (1 << 23)
+#define NAND_Ecc_P256o         (1 << 24)
+#define NAND_Ecc_P512o         (1 << 25)
+#define NAND_Ecc_P1024o                (1 << 26)
+#define NAND_Ecc_P2048o                (1 << 27)
+
+#define TF(value)      (value ? 1 : 0)
+
+#define P2048e(a)      (TF(a & NAND_Ecc_P2048e)        << 0)
+#define P2048o(a)      (TF(a & NAND_Ecc_P2048o)        << 1)
+#define P1e(a)         (TF(a & NAND_Ecc_P1e)           << 2)
+#define P1o(a)         (TF(a & NAND_Ecc_P1o)           << 3)
+#define P2e(a)         (TF(a & NAND_Ecc_P2e)           << 4)
+#define P2o(a)         (TF(a & NAND_Ecc_P2o)           << 5)
+#define P4e(a)         (TF(a & NAND_Ecc_P4e)           << 6)
+#define P4o(a)         (TF(a & NAND_Ecc_P4o)           << 7)
+
+#define P8e(a)         (TF(a & NAND_Ecc_P8e)           << 0)
+#define P8o(a)         (TF(a & NAND_Ecc_P8o)           << 1)
+#define P16e(a)                (TF(a & NAND_Ecc_P16e)          << 2)
+#define P16o(a)                (TF(a & NAND_Ecc_P16o)          << 3)
+#define P32e(a)                (TF(a & NAND_Ecc_P32e)          << 4)
+#define P32o(a)                (TF(a & NAND_Ecc_P32o)          << 5)
+#define P64e(a)                (TF(a & NAND_Ecc_P64e)          << 6)
+#define P64o(a)                (TF(a & NAND_Ecc_P64o)          << 7)
+
+#define P128e(a)       (TF(a & NAND_Ecc_P128e)         << 0)
+#define P128o(a)       (TF(a & NAND_Ecc_P128o)         << 1)
+#define P256e(a)       (TF(a & NAND_Ecc_P256e)         << 2)
+#define P256o(a)       (TF(a & NAND_Ecc_P256o)         << 3)
+#define P512e(a)       (TF(a & NAND_Ecc_P512e)         << 4)
+#define P512o(a)       (TF(a & NAND_Ecc_P512o)         << 5)
+#define P1024e(a)      (TF(a & NAND_Ecc_P1024e)        << 6)
+#define P1024o(a)      (TF(a & NAND_Ecc_P1024o)        << 7)
+
+#define P8e_s(a)       (TF(a & NAND_Ecc_P8e)           << 0)
+#define P8o_s(a)       (TF(a & NAND_Ecc_P8o)           << 1)
+#define P16e_s(a)      (TF(a & NAND_Ecc_P16e)          << 2)
+#define P16o_s(a)      (TF(a & NAND_Ecc_P16o)          << 3)
+#define P1e_s(a)       (TF(a & NAND_Ecc_P1e)           << 4)
+#define P1o_s(a)       (TF(a & NAND_Ecc_P1o)           << 5)
+#define P2e_s(a)       (TF(a & NAND_Ecc_P2e)           << 6)
+#define P2o_s(a)       (TF(a & NAND_Ecc_P2o)           << 7)
+
+#define P4e_s(a)       (TF(a & NAND_Ecc_P4e)           << 0)
+#define P4o_s(a)       (TF(a & NAND_Ecc_P4o)           << 1)
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+struct omap_nand_info {
+       struct nand_hw_control          controller;
+       struct omap_nand_platform_data  *pdata;
+       struct mtd_info                 mtd;
+       struct mtd_partition            *parts;
+       struct nand_chip                nand;
+       struct platform_device          *pdev;
+
+       int                             gpmc_cs;
+       unsigned long                   phys_base;
+       void __iomem                    *gpmc_cs_baseaddr;
+       void __iomem                    *gpmc_baseaddr;
+};
+
+/*
+ * omap_nand_wp - This function enable or disable the Write Protect feature on
+ * NAND device
+ * @mtd: MTD device structure
+ * @mode: WP ON/OFF
+ */
+static void omap_nand_wp(struct mtd_info *mtd, int mode)
+{
+       struct omap_nand_info *info = container_of(mtd,
+                                               struct omap_nand_info, mtd);
+
+       unsigned long config = __raw_readl(info->gpmc_baseaddr + GPMC_CONFIG);
+
+       if (mode)
+               config &= ~(NAND_WP_BIT);       /* WP is ON */
+       else
+               config |= (NAND_WP_BIT);        /* WP is OFF */
+
+       __raw_writel(config, (info->gpmc_baseaddr + GPMC_CONFIG));
+}
+
+/*
+ * hardware specific access to control-lines
+ * NOTE: boards may use different bits for these!!
+ *
+ * ctrl:
+ * NAND_NCE: bit 0 - don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ */
+static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct omap_nand_info *info = container_of(mtd,
+                                       struct omap_nand_info, mtd);
+       switch (ctrl) {
+       case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
+               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_COMMAND;
+               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_DATA;
+               break;
+
+       case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
+               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_ADDRESS;
+               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_DATA;
+               break;
+
+       case NAND_CTRL_CHANGE | NAND_NCE:
+               info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_DATA;
+               info->nand.IO_ADDR_R = info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_DATA;
+               break;
+       }
+
+       if (cmd != NAND_CMD_NONE)
+               __raw_writeb(cmd, info->nand.IO_ADDR_W);
+}
+
+/*
+ * omap_read_buf16 - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct nand_chip *nand = mtd->priv;
+
+       __raw_readsl(nand->IO_ADDR_R, buf, len / 2);
+}
+
+/*
+ * omap_write_buf16 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf16(struct mtd_info *mtd, const u_char * buf, int len)
+{
+       struct omap_nand_info *info = container_of(mtd,
+                                               struct omap_nand_info, mtd);
+       u16 *p = (u16 *) buf;
+
+       /* FIXME try bursts of writesw() or DMA ... */
+       len >>= 1;
+
+       while (len--) {
+               writew(*p++, info->nand.IO_ADDR_W);
+
+               while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
+                                               GPMC_STATUS) & GPMC_BUF_FULL));
+       }
+}
+/*
+ * omap_verify_buf - Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int omap_verify_buf(struct mtd_info *mtd, const u_char * buf, int len)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       u16 *p = (u16 *) buf;
+
+       len >>= 1;
+
+       while (len--) {
+
+               if (*p++ != cpu_to_le16(readw(info->nand.IO_ADDR_R)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
+/*
+ * omap_hwecc_init-Initialize the Hardware ECC for NAND flash in GPMC controller
+ * @mtd: MTD device structure
+ */
+static void omap_hwecc_init(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       register struct nand_chip *chip = mtd->priv;
+       unsigned long val = 0x0;
+
+       /* Read from ECC Control Register */
+       val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+       /* Clear all ECC | Enable Reg1 */
+       val = ((0x00000001<<8) | 0x00000001);
+       __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+
+       /* Read from ECC Size Config Register */
+       val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+       /* ECCSIZE1=512 | Select eccResultsize[0-3] */
+       val = ((((chip->ecc.size >> 1) - 1) << 22) | (0x0000000F));
+       __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_SIZE_CONFIG);
+}
+
+/*
+ * gen_true_ecc - This function will generate true ECC value, which can be used
+ * when correcting data read from NAND flash memory core
+ * @ecc_buf: buffer to store ecc code
+ */
+static void gen_true_ecc(u8 *ecc_buf)
+{
+       u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) |
+               ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8);
+
+       ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) |
+                       P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
+       ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) |
+                       P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+       ecc_buf[2] = ~(P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) |
+                       P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+/*
+ * omap_compare_ecc - This function compares two ECC's and indicates if there
+ * is an error. If the error can be corrected it will be corrected to the
+ * buffer
+ * @ecc_data1:  ecc code from nand spare area
+ * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
+ * @page_data:  page data
+ */
+static int omap_compare_ecc(u8 *ecc_data1,     /* read from NAND memory */
+                           u8 *ecc_data2,      /* read from register */
+                           u8 *page_data)
+{
+       uint    i;
+       u8      tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+       u8      comp0_bit[8], comp1_bit[8], comp2_bit[8];
+       u8      ecc_bit[24];
+       u8      ecc_sum = 0;
+       u8      find_bit = 0;
+       uint    find_byte = 0;
+       int     isEccFF;
+
+       isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+       gen_true_ecc(ecc_data1);
+       gen_true_ecc(ecc_data2);
+
+       for (i = 0; i <= 2; i++) {
+               *(ecc_data1 + i) = ~(*(ecc_data1 + i));
+               *(ecc_data2 + i) = ~(*(ecc_data2 + i));
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp0_bit[i]     = *ecc_data1 % 2;
+               *ecc_data1      = *ecc_data1 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp1_bit[i]      = *(ecc_data1 + 1) % 2;
+               *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               tmp2_bit[i]      = *(ecc_data1 + 2) % 2;
+               *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp0_bit[i]     = *ecc_data2 % 2;
+               *ecc_data2       = *ecc_data2 / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+               *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+       }
+
+       for (i = 0; i < 8; i++) {
+               comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+               *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+       }
+
+       for (i = 0; i < 6; i++)
+               ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+       for (i = 0; i < 8; i++)
+               ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+       ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+       ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+       for (i = 0; i < 24; i++)
+               ecc_sum += ecc_bit[i];
+
+       switch (ecc_sum) {
+       case 0:
+               /* Not reached because this function is not called if
+                *  ECC values are equal
+                */
+               return 0;
+
+       case 1:
+               /* Uncorrectable error */
+               DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+               return -1;
+
+       case 11:
+               /* UN-Correctable error */
+               DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n");
+               return -1;
+
+       case 12:
+               /* Correctable error */
+               find_byte = (ecc_bit[23] << 8) +
+                           (ecc_bit[21] << 7) +
+                           (ecc_bit[19] << 6) +
+                           (ecc_bit[17] << 5) +
+                           (ecc_bit[15] << 4) +
+                           (ecc_bit[13] << 3) +
+                           (ecc_bit[11] << 2) +
+                           (ecc_bit[9]  << 1) +
+                           ecc_bit[7];
+
+               find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+               DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at "
+                               "offset: %d, bit: %d\n", find_byte, find_bit);
+
+               page_data[find_byte] ^= (1 << find_bit);
+
+               return 0;
+       default:
+               if (isEccFF) {
+                       if (ecc_data2[0] == 0 &&
+                           ecc_data2[1] == 0 &&
+                           ecc_data2[2] == 0)
+                               return 0;
+               }
+               DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+               return -1;
+       }
+}
+
+/*
+ * omap_correct_data - Compares the ecc read from nand spare area with ECC
+ * registers values and corrects one bit error if it has occured
+ * @mtd: MTD device structure
+ * @dat: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from ECC registers
+ */
+static int omap_correct_data(struct mtd_info *mtd, u_char * dat,
+                               u_char * read_ecc, u_char * calc_ecc)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       int blockCnt = 0, i = 0, ret = 0;
+
+       /* Ex NAND_ECC_HW12_2048 */
+       if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+                       (info->nand.ecc.size  == 2048))
+               blockCnt = 4;
+       else
+               blockCnt = 1;
+
+       for (i = 0; i < blockCnt; i++) {
+               if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+                       ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+                       if (ret < 0) return ret;
+               }
+               read_ecc += 3;
+               calc_ecc += 3;
+               dat      += 512;
+       }
+       return 0;
+}
+
+/*
+ * omap_calcuate_ecc - Generate non-inverted ECC bytes.
+ * Using noninverted ECC can be considered ugly since writing a blank
+ * page ie. padding will clear the ECC bytes. This is no problem as long
+ * nobody is trying to write data on the seemingly unused page. Reading
+ * an erased page will produce an ECC mismatch between generated and read
+ * ECC bytes that has to be dealt with separately.
+ * @mtd: MTD device structure
+ * @dat: The pointer to data on which ecc is computed
+ * @ecc_code: The ecc_code buffer
+ */
+static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+                               u_char *ecc_code)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       unsigned long val = 0x0;
+       unsigned long reg;
+
+       /* Start Reading from HW ECC1_Result = 0x200 */
+       reg = (unsigned long)(info->gpmc_baseaddr + GPMC_ECC1_RESULT);
+       val = __raw_readl(reg);
+       *ecc_code++ = val;          /* P128e, ..., P1e */
+       *ecc_code++ = val >> 16;    /* P128o, ..., P1o */
+       /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+       *ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
+       reg += 4;
+
+       return 0;
+}
+
+/*
+ * omap_enable_hwecc - This function enables the hardware ecc functionality
+ * @mtd: MTD device structure
+ * @mode: Read/Write mode
+ */
+static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       register struct nand_chip *chip = mtd->priv;
+       unsigned int dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+       unsigned long val = __raw_readl(info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+
+       switch (mode) {
+       case NAND_ECC_READ    :
+               __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+               val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+               break;
+       case NAND_ECC_READSYN :
+                __raw_writel(0x100, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+               val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+               break;
+       case NAND_ECC_WRITE   :
+               __raw_writel(0x101, info->gpmc_baseaddr + GPMC_ECC_CONTROL);
+               /* (ECC 16 or 8 bit col) | ( CS  )  | ECC Enable */
+               val = (dev_width << 7) | (info->gpmc_cs << 1) | (0x1);
+               break;
+       default:
+               DEBUG(MTD_DEBUG_LEVEL0, "Error: Unrecognized Mode[%d]!\n",
+                                       mode);
+               break;
+       }
+
+       __raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
+}
+#endif
+
+/*
+ * omap_wait - Wait function is called during Program and erase
+ * operations and the way it is called from MTD layer, we should wait
+ * till the NAND chip is ready after the programming/erase operation
+ * has completed.
+ * @mtd: MTD device structure
+ * @chip: NAND Chip structure
+ */
+static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+       register struct nand_chip *this = mtd->priv;
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       int status = 0;
+
+       this->IO_ADDR_W = (void *) info->gpmc_cs_baseaddr +
+                                               GPMC_CS_NAND_COMMAND;
+       this->IO_ADDR_R = (void *) info->gpmc_cs_baseaddr + GPMC_CS_NAND_DATA;
+
+       while (!(status & 0x40)) {
+                __raw_writeb(NAND_CMD_STATUS & 0xFF, this->IO_ADDR_W);
+               status = __raw_readb(this->IO_ADDR_R);
+       }
+       return status;
+}
+
+/*
+ * omap_dev_ready - calls the platform specific dev_ready function
+ * @mtd: MTD device structure
+ */
+static int omap_dev_ready(struct mtd_info *mtd)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                       mtd);
+       unsigned int val = __raw_readl(info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+
+       if ((val & 0x100) == 0x100) {
+               /* Clear IRQ Interrupt */
+               val |= 0x100;
+               val &= ~(0x0);
+               __raw_writel(val, info->gpmc_baseaddr + GPMC_IRQ_STATUS);
+       } else {
+               unsigned int cnt = 0;
+               while (cnt++ < 0x1FF) {
+                       if  ((val & 0x100) == 0x100)
+                               return 0;
+                       val = __raw_readl(info->gpmc_baseaddr +
+                                                       GPMC_IRQ_STATUS);
+               }
+       }
+
+       return 1;
+}
+
+static int __devinit omap_nand_probe(struct platform_device *pdev)
+{
+       struct omap_nand_info           *info;
+       struct omap_nand_platform_data  *pdata;
+       int                             err;
+       unsigned long                   val;
+
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "platform data missing\n");
+               return -ENODEV;
+       }
+
+       info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL);
+       if (!info) return -ENOMEM;
+
+       platform_set_drvdata(pdev, info);
+
+       spin_lock_init(&info->controller.lock);
+       init_waitqueue_head(&info->controller.wq);
+
+       info->pdev = pdev;
+
+       info->gpmc_cs           = pdata->cs;
+       info->gpmc_baseaddr     = pdata->gpmc_baseaddr;
+       info->gpmc_cs_baseaddr  = pdata->gpmc_cs_baseaddr;
+
+       info->mtd.priv          = &info->nand;
+       info->mtd.name          = pdev->dev.bus_id;
+       info->mtd.owner         = THIS_MODULE;
+
+       err = gpmc_cs_request(info->gpmc_cs, NAND_IO_SIZE, &info->phys_base);
+       if (err < 0) {
+               dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+               goto out_free_info;
+       }
+
+       /* Enable RD PIN Monitoring Reg */
+       if (pdata->dev_ready) {
+               val  = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1);
+               val |= WR_RD_PIN_MONITORING;
+               gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG1, val);
+       }
+
+       val  = gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG7);
+       val &= ~(0xf << 8);
+       val |=  (0xc & 0xf) << 8;
+       gpmc_cs_write_reg(info->gpmc_cs, GPMC_CS_CONFIG7, val);
+
+       /* NAND write protect off */
+       omap_nand_wp(&info->mtd, NAND_WP_OFF);
+
+       if (!request_mem_region(info->phys_base, NAND_IO_SIZE,
+                               pdev->dev.driver->name)) {
+               err = -EBUSY;
+               goto out_free_cs;
+       }
+
+       info->nand.IO_ADDR_R = ioremap(info->phys_base, NAND_IO_SIZE);
+       if (!info->nand.IO_ADDR_R) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+       info->nand.controller = &info->controller;
+
+       info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
+       info->nand.cmd_ctrl  = omap_hwcontrol;
+
+       /* REVISIT:  only supports 16-bit NAND flash */
+
+       info->nand.read_buf   = omap_read_buf16;
+       info->nand.write_buf  = omap_write_buf16;
+       info->nand.verify_buf = omap_verify_buf;
+
+       /*
+       * If RDY/BSY line is connected to OMAP then use the omap ready funcrtion
+       * and the generic nand_wait function which reads the status register
+       * after monitoring the RDY/BSY line.Otherwise use a standard chip delay
+       * which is slightly more than tR (AC Timing) of the NAND device and read
+       * status register until you get a failure or success
+       */
+       if (pdata->dev_ready) {
+               info->nand.dev_ready = omap_dev_ready;
+               info->nand.chip_delay = 0;
+       } else {
+               info->nand.waitfunc = omap_wait;
+               info->nand.chip_delay = 50;
+       }
+
+       info->nand.options  |= NAND_SKIP_BBTSCAN;
+       if ((gpmc_cs_read_reg(info->gpmc_cs, GPMC_CS_CONFIG1) & 0x3000)
+                                                               == 0x1000)
+               info->nand.options  |= NAND_BUSWIDTH_16;
+
+#ifdef CONFIG_MTD_NAND_OMAP_HWECC
+       info->nand.ecc.bytes            = 3;
+       info->nand.ecc.size             = 512;
+       info->nand.ecc.calculate        = omap_calculate_ecc;
+       info->nand.ecc.hwctl            = omap_enable_hwecc;
+       info->nand.ecc.correct          = omap_correct_data;
+       info->nand.ecc.mode             = NAND_ECC_HW;
+
+       /* init HW ECC */
+       omap_hwecc_init(&info->mtd);
+#else
+       info->nand.ecc.mode = NAND_ECC_SOFT;
+#endif
+
+       /* DIP switches on some boards change between 8 and 16 bit
+        * bus widths for flash.  Try the other width if the first try fails.
+        */
+       if (nand_scan(&info->mtd, 1)) {
+               info->nand.options ^= NAND_BUSWIDTH_16;
+               if (nand_scan(&info->mtd, 1)) {
+                       err = -ENXIO;
+                       goto out_release_mem_region;
+               }
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(&info->mtd, info->parts, err);
+       else if (pdata->parts)
+               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               add_mtd_device(&info->mtd);
+
+       platform_set_drvdata(pdev, &info->mtd);
+
+       return 0;
+
+out_release_mem_region:
+       release_mem_region(info->phys_base, NAND_IO_SIZE);
+out_free_cs:
+       gpmc_cs_free(info->gpmc_cs);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int omap_nand_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct omap_nand_info *info = mtd->priv;
+
+       platform_set_drvdata(pdev, NULL);
+       /* Release NAND device, its internal structures and partitions */
+       nand_release(&info->mtd);
+       iounmap(info->nand.IO_ADDR_R);
+       kfree(&info->mtd);
+       return 0;
+}
+
+static struct platform_driver omap_nand_driver = {
+       .probe          = omap_nand_probe,
+       .remove         = omap_nand_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init omap_nand_init(void)
+{
+       printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
+       return platform_driver_register(&omap_nand_driver);
+}
+
+static void __exit omap_nand_exit(void)
+{
+       platform_driver_unregister(&omap_nand_driver);
+}
+
+module_init(omap_nand_init);
+module_exit(omap_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Glue layer for NAND flash on TI OMAP boards");
index cb41cbca64f7e63394f352820eb90cc610bac6f8..2d7c301d0d1edfd4ffb69578f3fc2b0b34d0557b 100644 (file)
@@ -27,6 +27,13 @@ config MTD_ONENAND_GENERIC
        help
          Support for OneNAND flash via platform device driver.
 
+config MTD_ONENAND_OMAP2
+       tristate "OneNAND on OMAP2/OMAP3 support"
+       depends on MTD_ONENAND && (ARCH_OMAP2 || ARCH_OMAP3)
+       help
+         Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU
+         via the GPMC memory controller.
+
 config MTD_ONENAND_OTP
        bool "OneNAND OTP Support"
        help
index 4d2eacfd7e11a761c3cec319f34c735d0fc0222b..64b6cc61a5209241145a4a3e1856dcb39a96d19c 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_ONENAND)               += onenand.o
 
 # Board specific.
 obj-$(CONFIG_MTD_ONENAND_GENERIC)      += generic.o
+obj-$(CONFIG_MTD_ONENAND_OMAP2)                += omap2.o
 
 # Simulator
 obj-$(CONFIG_MTD_ONENAND_SIM)          += onenand_sim.o
diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c
new file mode 100644 (file)
index 0000000..a9885d1
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+ *  linux/drivers/mtd/onenand/omap2.c
+ *
+ *  OneNAND driver for OMAP2 / OMAP3
+ *
+ *  Copyright (C) 2005-2006 Nokia Corporation
+ *
+ *  Author: Jarkko Lavinen <jarkko.lavinen@nokia.com> and Juha Yrjola
+ *  IRQ and DMA support written by Timo Teras
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+#include <mach/gpmc.h>
+#include <mach/onenand.h>
+#include <mach/gpio.h>
+#include <mach/pm.h>
+
+#include <linux/dma-mapping.h>
+#include <asm/dma-mapping.h>
+#include <mach/dma.h>
+
+#include <mach/board.h>
+
+#define DRIVER_NAME "omap2-onenand"
+
+#define ONENAND_IO_SIZE                SZ_128K
+#define ONENAND_BUFRAM_SIZE    (1024 * 5)
+
+struct omap2_onenand {
+       struct platform_device *pdev;
+       int gpmc_cs;
+       unsigned long phys_base;
+       int gpio_irq;
+       struct mtd_info mtd;
+       struct mtd_partition *parts;
+       struct onenand_chip onenand;
+       struct completion irq_done;
+       struct completion dma_done;
+       int dma_channel;
+       int freq;
+       int (*setup)(void __iomem *base, int freq);
+};
+
+static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data)
+{
+       struct omap2_onenand *c = data;
+
+       complete(&c->dma_done);
+}
+
+static irqreturn_t omap2_onenand_interrupt(int irq, void *dev_id)
+{
+       struct omap2_onenand *c = dev_id;
+
+       complete(&c->irq_done);
+
+       return IRQ_HANDLED;
+}
+
+static inline unsigned short read_reg(struct omap2_onenand *c, int reg)
+{
+       return readw(c->onenand.base + reg);
+}
+
+static inline void write_reg(struct omap2_onenand *c, unsigned short value,
+                            int reg)
+{
+       writew(value, c->onenand.base + reg);
+}
+
+static void wait_err(char *msg, int state, unsigned int ctrl, unsigned int intr)
+{
+       printk(KERN_ERR "onenand_wait: %s! state %d ctrl 0x%04x intr 0x%04x\n",
+              msg, state, ctrl, intr);
+}
+
+static void wait_warn(char *msg, int state, unsigned int ctrl,
+                     unsigned int intr)
+{
+       printk(KERN_WARNING "onenand_wait: %s! state %d ctrl 0x%04x "
+              "intr 0x%04x\n", msg, state, ctrl, intr);
+}
+
+static int omap2_onenand_wait(struct mtd_info *mtd, int state)
+{
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       unsigned int intr = 0;
+       unsigned int ctrl;
+       unsigned long timeout;
+       u32 syscfg;
+
+       if (state == FL_RESETING) {
+               int i;
+
+               for (i = 0; i < 20; i++) {
+                       udelay(1);
+                       intr = read_reg(c, ONENAND_REG_INTERRUPT);
+                       if (intr & ONENAND_INT_MASTER)
+                               break;
+               }
+               ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+               if (ctrl & ONENAND_CTRL_ERROR) {
+                       wait_err("controller error", state, ctrl, intr);
+                       return -EIO;
+               }
+               if (!(intr & ONENAND_INT_RESET)) {
+                       wait_err("timeout", state, ctrl, intr);
+                       return -EIO;
+               }
+               return 0;
+       }
+
+       if (state != FL_READING) {
+               int result;
+
+               /* Turn interrupts on */
+               syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+               if (!(syscfg & ONENAND_SYS_CFG1_IOBE)) {
+                       syscfg |= ONENAND_SYS_CFG1_IOBE;
+                       write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+                       if (cpu_is_omap34xx())
+                               /* Add a delay to let GPIO settle */
+                               syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+               }
+
+               INIT_COMPLETION(c->irq_done);
+               if (c->gpio_irq) {
+                       result = omap_get_gpio_datain(c->gpio_irq);
+                       if (result == -1) {
+                               ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+                               intr = read_reg(c, ONENAND_REG_INTERRUPT);
+                               wait_err("gpio error", state, ctrl, intr);
+                               return -EIO;
+                       }
+               } else
+                       result = 0;
+               if (result == 0) {
+                       int retry_cnt = 0;
+retry:
+                       result = wait_for_completion_timeout(&c->irq_done,
+                                                   msecs_to_jiffies(20));
+                       if (result == 0) {
+                               /* Timeout after 20ms */
+                               ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+                               if (ctrl & ONENAND_CTRL_ONGO) {
+                                       /*
+                                        * The operation seems to be still going
+                                        * so give it some more time.
+                                        */
+                                       retry_cnt += 1;
+                                       if (retry_cnt < 3)
+                                               goto retry;
+                                       intr = read_reg(c,
+                                                       ONENAND_REG_INTERRUPT);
+                                       wait_err("timeout", state, ctrl, intr);
+                                       return -EIO;
+                               }
+                               intr = read_reg(c, ONENAND_REG_INTERRUPT);
+                               if ((intr & ONENAND_INT_MASTER) == 0)
+                                       wait_warn("timeout", state, ctrl, intr);
+                       }
+               }
+       } else {
+               /* Turn interrupts off */
+               syscfg = read_reg(c, ONENAND_REG_SYS_CFG1);
+               syscfg &= ~ONENAND_SYS_CFG1_IOBE;
+               write_reg(c, syscfg, ONENAND_REG_SYS_CFG1);
+
+               timeout = jiffies + msecs_to_jiffies(20);
+               while (time_before(jiffies, timeout)) {
+                       intr = read_reg(c, ONENAND_REG_INTERRUPT);
+                       if (intr & ONENAND_INT_MASTER)
+                               break;
+               }
+       }
+
+       intr = read_reg(c, ONENAND_REG_INTERRUPT);
+       ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS);
+
+       if (intr & ONENAND_INT_READ) {
+               int ecc = read_reg(c, ONENAND_REG_ECC_STATUS);
+
+               if (ecc) {
+                       unsigned int addr1, addr8;
+
+                       addr1 = read_reg(c, ONENAND_REG_START_ADDRESS1);
+                       addr8 = read_reg(c, ONENAND_REG_START_ADDRESS8);
+                       if (ecc & ONENAND_ECC_2BIT_ALL) {
+                               printk(KERN_ERR "onenand_wait: ECC error = "
+                                      "0x%04x, addr1 %#x, addr8 %#x\n",
+                                      ecc, addr1, addr8);
+                               mtd->ecc_stats.failed++;
+                               return -EBADMSG;
+                       } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+                               printk(KERN_NOTICE "onenand_wait: correctable "
+                                      "ECC error = 0x%04x, addr1 %#x, "
+                                      "addr8 %#x\n", ecc, addr1, addr8);
+                               mtd->ecc_stats.corrected++;
+                       }
+               }
+       } else if (state == FL_READING) {
+               wait_err("timeout", state, ctrl, intr);
+               return -EIO;
+       }
+
+       if (ctrl & ONENAND_CTRL_ERROR) {
+               wait_err("controller error", state, ctrl, intr);
+               if (ctrl & ONENAND_CTRL_LOCK)
+                       printk(KERN_ERR "onenand_wait: "
+                                       "Device is write protected!!!\n");
+               return -EIO;
+       }
+
+       if (ctrl & 0xFE9F)
+               wait_warn("unexpected controller status", state, ctrl, intr);
+
+       return 0;
+}
+
+static inline int omap2_onenand_bufferram_offset(struct mtd_info *mtd, int area)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       if (ONENAND_CURRENT_BUFFERRAM(this)) {
+               if (area == ONENAND_DATARAM)
+                       return mtd->writesize;
+               if (area == ONENAND_SPARERAM)
+                       return mtd->oobsize;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) || defined(MULTI_OMAP2)
+
+static int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+                                       unsigned char *buffer, int offset,
+                                       size_t count)
+{
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       struct onenand_chip *this = mtd->priv;
+       dma_addr_t dma_src, dma_dst;
+       int bram_offset;
+       unsigned long timeout;
+       void *buf = (void *)buffer;
+       size_t xtra;
+       volatile unsigned *done;
+
+       bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+       if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+               goto out_copy;
+
+       if (buf >= high_memory) {
+               struct page *p1;
+
+               if (((size_t)buf & PAGE_MASK) !=
+                   ((size_t)(buf + count - 1) & PAGE_MASK))
+                       goto out_copy;
+               p1 = vmalloc_to_page(buf);
+               if (!p1)
+                       goto out_copy;
+               buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+       }
+
+       xtra = count & 3;
+       if (xtra) {
+               count -= xtra;
+               memcpy(buf + count, this->base + bram_offset + count, xtra);
+       }
+
+       dma_src = c->phys_base + bram_offset;
+       dma_dst = dma_map_single(&c->pdev->dev, buf, count, DMA_FROM_DEVICE);
+       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+               dev_err(&c->pdev->dev,
+                       "Couldn't DMA map a %d byte buffer\n",
+                       count);
+               goto out_copy;
+       }
+
+       omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+                                    count >> 2, 1, 0, 0, 0);
+       omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                               dma_src, 0, 0);
+       omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                                dma_dst, 0, 0);
+
+       INIT_COMPLETION(c->dma_done);
+       omap_start_dma(c->dma_channel);
+
+       timeout = jiffies + msecs_to_jiffies(20);
+       done = &c->dma_done.done;
+       while (time_before(jiffies, timeout))
+               if (*done)
+                       break;
+
+       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+       if (!*done) {
+               dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+               goto out_copy;
+       }
+
+       return 0;
+
+out_copy:
+       memcpy(buf, this->base + bram_offset, count);
+       return 0;
+}
+
+static int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+                                        const unsigned char *buffer,
+                                        int offset, size_t count)
+{
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       struct onenand_chip *this = mtd->priv;
+       dma_addr_t dma_src, dma_dst;
+       int bram_offset;
+       unsigned long timeout;
+       void *buf = (void *)buffer;
+       volatile unsigned *done;
+
+       bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+       if (bram_offset & 3 || (size_t)buf & 3 || count < 384)
+               goto out_copy;
+
+       /* panic_write() may be in an interrupt context */
+       if (in_interrupt())
+               goto out_copy;
+
+       if (buf >= high_memory) {
+               struct page *p1;
+
+               if (((size_t)buf & PAGE_MASK) !=
+                   ((size_t)(buf + count - 1) & PAGE_MASK))
+                       goto out_copy;
+               p1 = vmalloc_to_page(buf);
+               if (!p1)
+                       goto out_copy;
+               buf = page_address(p1) + ((size_t)buf & ~PAGE_MASK);
+       }
+
+       dma_src = dma_map_single(&c->pdev->dev, buf, count, DMA_TO_DEVICE);
+       dma_dst = c->phys_base + bram_offset;
+       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+               dev_err(&c->pdev->dev,
+                       "Couldn't DMA map a %d byte buffer\n",
+                       count);
+               return -1;
+       }
+
+       omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+                                    count >> 2, 1, 0, 0, 0);
+       omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                               dma_src, 0, 0);
+       omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                                dma_dst, 0, 0);
+
+       INIT_COMPLETION(c->dma_done);
+       omap_start_dma(c->dma_channel);
+
+       timeout = jiffies + msecs_to_jiffies(20);
+       done = &c->dma_done.done;
+       while (time_before(jiffies, timeout))
+               if (*done)
+                       break;
+
+       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+       if (!*done) {
+               dev_err(&c->pdev->dev, "timeout waiting for DMA\n");
+               goto out_copy;
+       }
+
+       return 0;
+
+out_copy:
+       memcpy(this->base + bram_offset, buf, count);
+       return 0;
+}
+
+#else
+
+int omap3_onenand_read_bufferram(struct mtd_info *mtd, int area,
+                                unsigned char *buffer, int offset,
+                                size_t count);
+
+int omap3_onenand_write_bufferram(struct mtd_info *mtd, int area,
+                                 const unsigned char *buffer,
+                                 int offset, size_t count);
+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(MULTI_OMAP2)
+
+static int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+                                       unsigned char *buffer, int offset,
+                                       size_t count)
+{
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       struct onenand_chip *this = mtd->priv;
+       dma_addr_t dma_src, dma_dst;
+       int bram_offset;
+
+       bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+       /* DMA is not used.  Revisit PM requirements before enabling it. */
+       if (1 || (c->dma_channel < 0) ||
+           ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+           (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+               memcpy(buffer, (__force void *)(this->base + bram_offset),
+                      count);
+               return 0;
+       }
+
+       dma_src = c->phys_base + bram_offset;
+       dma_dst = dma_map_single(&c->pdev->dev, buffer, count,
+                                DMA_FROM_DEVICE);
+       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+               dev_err(&c->pdev->dev,
+                       "Couldn't DMA map a %d byte buffer\n",
+                       count);
+               return -1;
+       }
+
+       omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S32,
+                                    count / 4, 1, 0, 0, 0);
+       omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                               dma_src, 0, 0);
+       omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                                dma_dst, 0, 0);
+
+       INIT_COMPLETION(c->dma_done);
+       omap_start_dma(c->dma_channel);
+       wait_for_completion(&c->dma_done);
+
+       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_FROM_DEVICE);
+
+       return 0;
+}
+
+static int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+                                        const unsigned char *buffer,
+                                        int offset, size_t count)
+{
+       struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd);
+       struct onenand_chip *this = mtd->priv;
+       dma_addr_t dma_src, dma_dst;
+       int bram_offset;
+
+       bram_offset = omap2_onenand_bufferram_offset(mtd, area) + area + offset;
+       /* DMA is not used.  Revisit PM requirements before enabling it. */
+       if (1 || (c->dma_channel < 0) ||
+           ((void *) buffer >= (void *) high_memory) || (bram_offset & 3) ||
+           (((unsigned int) buffer) & 3) || (count < 1024) || (count & 3)) {
+               memcpy((__force void *)(this->base + bram_offset), buffer,
+                      count);
+               return 0;
+       }
+
+       dma_src = dma_map_single(&c->pdev->dev, (void *) buffer, count,
+                                DMA_TO_DEVICE);
+       dma_dst = c->phys_base + bram_offset;
+       if (dma_mapping_error(&c->pdev->dev, dma_dst)) {
+               dev_err(&c->pdev->dev,
+                       "Couldn't DMA map a %d byte buffer\n",
+                       count);
+               return -1;
+       }
+
+       omap_set_dma_transfer_params(c->dma_channel, OMAP_DMA_DATA_TYPE_S16,
+                                    count / 2, 1, 0, 0, 0);
+       omap_set_dma_src_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                               dma_src, 0, 0);
+       omap_set_dma_dest_params(c->dma_channel, 0, OMAP_DMA_AMODE_POST_INC,
+                                dma_dst, 0, 0);
+
+       INIT_COMPLETION(c->dma_done);
+       omap_start_dma(c->dma_channel);
+       wait_for_completion(&c->dma_done);
+
+       dma_unmap_single(&c->pdev->dev, dma_dst, count, DMA_TO_DEVICE);
+
+       return 0;
+}
+
+#else
+
+int omap2_onenand_read_bufferram(struct mtd_info *mtd, int area,
+                                unsigned char *buffer, int offset,
+                                size_t count);
+
+int omap2_onenand_write_bufferram(struct mtd_info *mtd, int area,
+                                 const unsigned char *buffer,
+                                 int offset, size_t count);
+
+#endif
+
+static struct platform_driver omap2_onenand_driver;
+
+static int __adjust_timing(struct device *dev, void *data)
+{
+       int ret = 0;
+       struct omap2_onenand *c;
+
+       c = dev_get_drvdata(dev);
+
+       BUG_ON(c->setup == NULL);
+
+       /* DMA is not in use so this is all that is needed */
+       /* Revisit for OMAP3! */
+       ret = c->setup(c->onenand.base, c->freq);
+
+       return ret;
+}
+
+int omap2_onenand_rephase(void)
+{
+       return driver_for_each_device(&omap2_onenand_driver.driver, NULL,
+                                     NULL, __adjust_timing);
+}
+
+static void __devexit omap2_onenand_shutdown(struct platform_device *pdev)
+{
+       struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+       /* With certain content in the buffer RAM, the OMAP boot ROM code
+        * can recognize the flash chip incorrectly. Zero it out before
+        * soft reset.
+        */
+       memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE);
+}
+
+static int __devinit omap2_onenand_probe(struct platform_device *pdev)
+{
+       struct omap_onenand_platform_data *pdata;
+       struct omap2_onenand *c;
+       int r;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "platform data missing\n");
+               return -ENODEV;
+       }
+
+       c = kzalloc(sizeof(struct omap2_onenand), GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;
+
+       init_completion(&c->irq_done);
+       init_completion(&c->dma_done);
+       c->gpmc_cs = pdata->cs;
+       c->gpio_irq = pdata->gpio_irq;
+       c->dma_channel = pdata->dma_channel;
+       if (c->dma_channel < 0) {
+               /* if -1, don't use DMA */
+               c->gpio_irq = 0;
+       }
+
+       r = gpmc_cs_request(c->gpmc_cs, ONENAND_IO_SIZE, &c->phys_base);
+       if (r < 0) {
+               dev_err(&pdev->dev, "Cannot request GPMC CS\n");
+               goto err_kfree;
+       }
+
+       if (request_mem_region(c->phys_base, ONENAND_IO_SIZE,
+                              pdev->dev.driver->name) == NULL) {
+               dev_err(&pdev->dev, "Cannot reserve memory region at 0x%08lx, "
+                       "size: 0x%x\n", c->phys_base, ONENAND_IO_SIZE);
+               r = -EBUSY;
+               goto err_free_cs;
+       }
+       c->onenand.base = ioremap(c->phys_base, ONENAND_IO_SIZE);
+       if (c->onenand.base == NULL) {
+               r = -ENOMEM;
+               goto err_release_mem_region;
+       }
+
+       if (pdata->onenand_setup != NULL) {
+               r = pdata->onenand_setup(c->onenand.base, c->freq);
+               if (r < 0) {
+                       dev_err(&pdev->dev, "Onenand platform setup failed: "
+                               "%d\n", r);
+                       goto err_iounmap;
+               }
+               c->setup = pdata->onenand_setup;
+       }
+
+       if (c->gpio_irq) {
+               if ((r = omap_request_gpio(c->gpio_irq)) < 0) {
+                       dev_err(&pdev->dev,  "Failed to request GPIO%d for "
+                               "OneNAND\n", c->gpio_irq);
+                       goto err_iounmap;
+       }
+       omap_set_gpio_direction(c->gpio_irq, 1);
+
+       if ((r = request_irq(OMAP_GPIO_IRQ(c->gpio_irq),
+                            omap2_onenand_interrupt, IRQF_TRIGGER_RISING,
+                            pdev->dev.driver->name, c)) < 0)
+               goto err_release_gpio;
+       }
+
+       if (c->dma_channel >= 0) {
+               r = omap_request_dma(0, pdev->dev.driver->name,
+                                    omap2_onenand_dma_cb, (void *) c,
+                                    &c->dma_channel);
+               if (r == 0) {
+                       omap_set_dma_write_mode(c->dma_channel,
+                                               OMAP_DMA_WRITE_NON_POSTED);
+                       omap_set_dma_src_data_pack(c->dma_channel, 1);
+                       omap_set_dma_src_burst_mode(c->dma_channel,
+                                                   OMAP_DMA_DATA_BURST_8);
+                       omap_set_dma_dest_data_pack(c->dma_channel, 1);
+                       omap_set_dma_dest_burst_mode(c->dma_channel,
+                                                    OMAP_DMA_DATA_BURST_8);
+               } else {
+                       dev_info(&pdev->dev,
+                                "failed to allocate DMA for OneNAND, "
+                                "using PIO instead\n");
+                       c->dma_channel = -1;
+               }
+       }
+
+       dev_info(&pdev->dev, "initializing on CS%d, phys base 0x%08lx, virtual "
+                "base %p\n", c->gpmc_cs, c->phys_base,
+                c->onenand.base);
+
+       c->pdev = pdev;
+       c->mtd.name = pdev->dev.bus_id;
+       c->mtd.priv = &c->onenand;
+       c->mtd.owner = THIS_MODULE;
+
+       if (c->dma_channel >= 0) {
+               struct onenand_chip *this = &c->onenand;
+
+               this->wait = omap2_onenand_wait;
+               if (cpu_is_omap34xx()) {
+                       this->read_bufferram = omap3_onenand_read_bufferram;
+                       this->write_bufferram = omap3_onenand_write_bufferram;
+               } else {
+                       this->read_bufferram = omap2_onenand_read_bufferram;
+                       this->write_bufferram = omap2_onenand_write_bufferram;
+               }
+       }
+
+       if ((r = onenand_scan(&c->mtd, 1)) < 0)
+               goto err_release_dma;
+
+       switch ((c->onenand.version_id >> 4) & 0xf) {
+       case 0:
+               c->freq = 40;
+               break;
+       case 1:
+               c->freq = 54;
+               break;
+       case 2:
+               c->freq = 66;
+               break;
+       case 3:
+               c->freq = 83;
+               break;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (pdata->parts != NULL)
+               r = add_mtd_partitions(&c->mtd, pdata->parts,
+                                      pdata->nr_parts);
+       else
+#endif
+               r = add_mtd_device(&c->mtd);
+       if (r < 0)
+               goto err_release_onenand;
+
+       platform_set_drvdata(pdev, c);
+
+       return 0;
+
+err_release_onenand:
+       onenand_release(&c->mtd);
+err_release_dma:
+       if (c->dma_channel != -1)
+               omap_free_dma(c->dma_channel);
+       if (c->gpio_irq)
+               free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+err_release_gpio:
+       if (c->gpio_irq)
+               omap_free_gpio(c->gpio_irq);
+err_iounmap:
+       iounmap(c->onenand.base);
+err_release_mem_region:
+       release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+err_free_cs:
+       gpmc_cs_free(c->gpmc_cs);
+err_kfree:
+       kfree(c);
+
+       return r;
+}
+
+static int __devexit omap2_onenand_remove(struct platform_device *pdev)
+{
+       struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
+
+       BUG_ON(c == NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (c->parts)
+               del_mtd_partitions(&c->mtd);
+       else
+               del_mtd_device(&c->mtd);
+#else
+       del_mtd_device(&c->mtd);
+#endif
+
+       onenand_release(&c->mtd);
+       if (c->dma_channel != -1)
+               omap_free_dma(c->dma_channel);
+       omap2_onenand_shutdown(pdev);
+       platform_set_drvdata(pdev, NULL);
+       if (c->gpio_irq) {
+               free_irq(OMAP_GPIO_IRQ(c->gpio_irq), c);
+               omap_free_gpio(c->gpio_irq);
+       }
+       iounmap(c->onenand.base);
+       release_mem_region(c->phys_base, ONENAND_IO_SIZE);
+       kfree(c);
+
+       return 0;
+}
+
+static struct platform_driver omap2_onenand_driver = {
+       .probe          = omap2_onenand_probe,
+       .remove         = omap2_onenand_remove,
+       .shutdown       = omap2_onenand_shutdown,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap2_onenand_init(void)
+{
+       printk(KERN_INFO "OneNAND driver initializing\n");
+       return platform_driver_register(&omap2_onenand_driver);
+}
+
+static void __exit omap2_onenand_exit(void)
+{
+       platform_driver_unregister(&omap2_onenand_driver);
+}
+
+module_init(omap2_onenand_init);
+module_exit(omap2_onenand_exit);
+
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarkko Lavinen <jarkko.lavinen@nokia.com>");
+MODULE_DESCRIPTION("Glue layer for OneNAND flash on OMAP2 / OMAP3");
index 4a11296a951438df0730456206473bc40b363059..cd5867f6996a4bdac606de45e2ce083eccbbc386 100644 (file)
@@ -960,7 +960,7 @@ config SMC911X
        tristate "SMSC LAN911[5678] support"
        select CRC32
        select MII
-       depends on ARCH_PXA || SUPERH
+       depends on ARCH_PXA || SUPERH || SH_MAGIC_PANEL_R2 || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
          This is a driver for SMSC's LAN911x series of Ethernet chipsets
          including the new LAN9115, LAN9116, LAN9117, and LAN9118.
index e6317557a531e342d516f02ba8daa8bf360b2753..b83e25bde7b2b5abc7cca13b69808aadc62d0382 100644 (file)
@@ -342,5 +342,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 5d20fde32a246fd41081594e6559239b60c4bf23..49e6f062e05d649d112ecc2e535ccc34095b2902 100644 (file)
@@ -18,6 +18,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
 obj-$(CONFIG_AU1000_FIR)       += au1k_ir.o
 # SIR drivers
 obj-$(CONFIG_IRTTY_SIR)                += irtty-sir.o  sir-dev.o
diff --git a/drivers/net/irda/omap-ir.c b/drivers/net/irda/omap-ir.c
new file mode 100644 (file)
index 0000000..b706253
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *
+ *     Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 and H4 Platforms
+ *       (SIR/MIR/FIR modes)
+ *       (based on omap-sir.c)
+ *
+ * Copyright 2003 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *        source@mvista.com
+ *
+ * Copyright 2004 Texas Instruments.
+ *
+ *  This program is free software; you can redistribute         it and/or modify it
+ *  under  the terms of         the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED          ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,          INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED          TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN         CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ Modifications:
+ Feb 2004, Texas Instruments
+ - Ported to 2.6 kernel (Feb 2004).
+ *
+ Apr 2004, Texas Instruments
+ - Added support for H3 (Apr 2004).
+ Nov 2004, Texas Instruments
+ - Added support for Power Management.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include <linux/rtnetlink.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/dma.h>
+#include <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/irda.h>
+
+#define UART3_EFR_EN                   (1 << 4)
+#define UART3_MCR_EN_TCR_TLR           (1 << 6)
+
+#define UART3_LCR_WL_8                 (3 << 0)
+#define UART3_LCR_SP2                  (1 << 2)
+#define UART3_LCR_DIVEN                        (1 << 7)
+
+#define UART3_FCR_FIFO_EN              (1 << 0)
+#define UART3_FCR_FIFO_RX              (1 << 1)
+#define UART3_FCR_FIFO_TX              (1 << 2)
+#define UART3_FCR_FIFO_DMA1            (1 << 3)
+#define UART3_FCR_FIFO_TX_TRIG16       (1 << 4)
+#define UART3_FCR_FIFO_RX_TRIG16       (1 << 6)
+#define UART3_FCR_CONFIG       (\
+               UART3_FCR_FIFO_EN | UART3_FCR_FIFO_RX   |\
+               UART3_FCR_FIFO_TX | UART3_FCR_FIFO_DMA1 |\
+               UART3_FCR_FIFO_TX_TRIG16                |\
+               UART3_FCR_FIFO_RX_TRIG16)
+
+#define UART3_SCR_TX_TRIG1             (1 << 6)
+#define UART3_SCR_RX_TRIG1             (1 << 7)
+
+#define UART3_MDR1_RESET               (0x07)
+#define UART3_MDR1_SIR                 (1 << 0)
+#define UART3_MDR1_MIR                 (4 << 0)
+#define UART3_MDR1_FIR                 (5 << 0)
+#define UART3_MDR1_SIP_AUTO            (1 << 6)
+
+#define UART3_MDR2_TRIG1               (0 << 1)
+#define UART3_MDR2_IRTX_UNDERRUN       (1 << 0)
+
+#define UART3_ACERG_TX_UNDERRUN_DIS    (1 << 4)
+#define UART3_ACERG_SD_MODE_LOW                (1 << 6)
+#define UART3_ACERG_DIS_IR_RX          (1 << 5)
+
+#define UART3_IER_EOF                  (1 << 5)
+#define UART3_IER_CTS                  (1 << 7)
+
+#define UART3_IIR_TX_STATUS            (1 << 5)
+#define UART3_IIR_EOF                  (0x80)
+
+#define IS_FIR(omap_ir)                ((omap_ir)->speed >= 4000000)
+
+struct omap_irda {
+       unsigned char open;
+       int speed;              /* Current IrDA speed */
+       int newspeed;
+
+       struct net_device_stats stats;
+       struct irlap_cb *irlap;
+       struct qos_info qos;
+
+       int rx_dma_channel;
+       int tx_dma_channel;
+
+       dma_addr_t rx_buf_dma_phys;     /* Physical address of RX DMA buffer */
+       dma_addr_t tx_buf_dma_phys;     /* Physical address of TX DMA buffer */
+
+       void *rx_buf_dma_virt;          /* Virtual address of RX DMA buffer */
+       void *tx_buf_dma_virt;          /* Virtual address of TX DMA buffer */
+
+       struct device *dev;
+       struct omap_irda_config *pdata;
+};
+
+static void inline uart_reg_out(int idx, u8 val)
+{
+       omap_writeb(val, idx);
+}
+
+static u8 inline uart_reg_in(int idx)
+{
+       u8 b = omap_readb(idx);
+       return b;
+}
+
+/* forward declarations */
+extern void omap_stop_dma(int lch);
+static int omap_irda_set_speed(struct net_device *dev, int speed);
+
+static void omap_irda_start_rx_dma(struct omap_irda *omap_ir)
+{
+       /* Configure DMA */
+       omap_set_dma_src_params(omap_ir->rx_dma_channel, 0x3, 0x0,
+                               omap_ir->pdata->src_start,
+                               0, 0);
+
+       omap_enable_dma_irq(omap_ir->rx_dma_channel, 0x01);
+
+       omap_set_dma_dest_params(omap_ir->rx_dma_channel, 0x0, 0x1,
+                               omap_ir->rx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->rx_dma_channel, 0x0,
+                               IRDA_SKB_MAX_MTU, 0x1,
+                               0x0, omap_ir->pdata->rx_trigger, 0);
+
+       omap_start_dma(omap_ir->rx_dma_channel);
+}
+
+static void omap_start_tx_dma(struct omap_irda *omap_ir, int size)
+{
+       /* Configure DMA */
+       omap_set_dma_dest_params(omap_ir->tx_dma_channel, 0x03, 0x0,
+                               omap_ir->pdata->dest_start, 0, 0);
+
+       omap_enable_dma_irq(omap_ir->tx_dma_channel, 0x01);
+
+       omap_set_dma_src_params(omap_ir->tx_dma_channel, 0x0, 0x1,
+                               omap_ir->tx_buf_dma_phys,
+                               0, 0);
+
+       omap_set_dma_transfer_params(omap_ir->tx_dma_channel, 0x0, size, 0x1,
+                               0x0, omap_ir->pdata->tx_trigger, 0);
+
+       /* Start DMA */
+       omap_start_dma(omap_ir->tx_dma_channel);
+}
+
+/* DMA RX callback - normally, we should not go here,
+ * it calls only if something is going wrong
+ */
+static void omap_irda_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       printk(KERN_ERR "RX Transfer error or very big frame\n");
+
+       /* Clear interrupts */
+       uart_reg_in(UART3_IIR);
+
+       omap_ir->stats.rx_frame_errors++;
+
+       uart_reg_in(UART3_RESUME);
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+}
+
+/* DMA TX callback - calling when frame transfer has been finished */
+static void omap_irda_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+       struct net_device *dev = data;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /*Stop DMA controller */
+       omap_stop_dma(omap_ir->tx_dma_channel);
+}
+
+/*
+ * Set the IrDA communications speed.
+ * Interrupt have to be disabled here.
+ */
+static int omap_irda_startup(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       /* FIXME: use clk_* apis for UART3 clock*/
+       /* Enable UART3 clock and set UART3 to IrDA mode */
+       if (machine_is_omap_h2() || machine_is_omap_h3())
+               omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15),
+                               MOD_CONF_CTRL_0);
+
+       /* Only for H2?
+        */
+       if (omap_ir->pdata->transceiver_mode && machine_is_omap_h2()) {
+               /* Is it select_irda on H2 ? */
+               omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7,
+                                       FUNC_MUX_CTRL_A);
+               omap_ir->pdata->transceiver_mode(omap_ir->dev, IR_SIRMODE);
+       }
+
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);     /* Reset mode */
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+       uart_reg_out(UART3_LCR, 0xbf);  /* FIXME: Add #define */
+
+       uart_reg_out(UART3_EFR, UART3_EFR_EN);
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+
+       /* Enable access to UART3_TLR and UART3_TCR registers */
+       uart_reg_out(UART3_MCR, UART3_MCR_EN_TCR_TLR);
+
+       uart_reg_out(UART3_SCR, 0);
+       /* Set Rx trigger to 1 and Tx trigger to 1 */
+       uart_reg_out(UART3_TLR, 0);
+
+       /* Set LCR to 8 bits and 1 stop bit */
+       uart_reg_out(UART3_LCR, 0x03);
+
+       /* Clear RX and TX FIFO and enable FIFO */
+       /* Use DMA Req for transfers */
+       uart_reg_out(UART3_FCR, UART3_FCR_CONFIG);
+
+       uart_reg_out(UART3_MCR, 0);
+
+       uart_reg_out(UART3_SCR, UART3_SCR_TX_TRIG1 |
+                       UART3_SCR_RX_TRIG1);
+
+       /* Enable UART3 SIR Mode,(Frame-length method to end frames) */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_SIR);
+
+       /* Set Status FIFO trig to 1 */
+       uart_reg_out(UART3_MDR2, 0);
+
+       /* Enables RXIR input */
+       /* and disable TX underrun */
+       /* SEND_SIP pulse */
+       uart_reg_out(UART3_ACREG, UART3_ACERG_SD_MODE_LOW |
+                       UART3_ACERG_TX_UNDERRUN_DIS);
+
+       /* Enable EOF Interrupt only */
+       uart_reg_out(UART3_IER, UART3_IER_CTS | UART3_IER_EOF);
+
+       /* Set Maximum Received Frame size to 2048 bytes */
+       uart_reg_out(UART3_RXFLL, 0x00);
+       uart_reg_out(UART3_RXFLH, 0x08);
+
+       uart_reg_in(UART3_RESUME);
+
+       return 0;
+}
+
+static int omap_irda_shutdown(struct omap_irda *omap_ir)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       /* Disable all UART3 Interrupts */
+       uart_reg_out(UART3_IER, 0);
+
+       /* Disable UART3 and disable baud rate generator */
+       uart_reg_out(UART3_MDR1, UART3_MDR1_RESET);
+
+       /* set SD_MODE pin to high and Disable RX IR */
+       uart_reg_out(UART3_ACREG, (UART3_ACERG_DIS_IR_RX |
+                       ~(UART3_ACERG_SD_MODE_LOW)));
+
+       /* Clear DLH and DLL */
+       uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+       uart_reg_out(UART3_DLL, 0);
+       uart_reg_out(UART3_DLH, 0);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static irqreturn_t
+omap_irda_irq(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       u8 status;
+       int w = 0;
+
+       /* Clear EOF interrupt */
+       status = uart_reg_in(UART3_IIR);
+
+       if (status & UART3_IIR_TX_STATUS) {
+               u8 mdr2 = uart_reg_in(UART3_MDR2);
+               if (mdr2 & UART3_MDR2_IRTX_UNDERRUN)
+                       printk(KERN_ERR "IrDA Buffer underrun error\n");
+
+               omap_ir->stats.tx_packets++;
+
+               if (omap_ir->newspeed) {
+                       omap_irda_set_speed(dev, omap_ir->newspeed);
+                       omap_ir->newspeed = 0;
+               }
+
+               netif_wake_queue(dev);
+               if (!(status & UART3_IIR_EOF))
+                       return IRQ_HANDLED;
+       }
+
+       /* Stop DMA and if there are no errors, send frame to upper layer */
+       omap_stop_dma(omap_ir->rx_dma_channel);
+
+       status = uart_reg_in(UART3_SFLSR);      /* Take a frame status */
+
+       if (status != 0) {      /* Bad frame? */
+               omap_ir->stats.rx_frame_errors++;
+               uart_reg_in(UART3_RESUME);
+       } else {
+               /* We got a frame! */
+               skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+
+               if (!skb) {
+                       printk(KERN_ERR "omap_sir: out of memory for RX SKB\n");
+                       return IRQ_HANDLED;
+               }
+               /*
+                * Align any IP headers that may be contained
+                * within the frame.
+                */
+
+               skb_reserve(skb, 1);
+
+               w = omap_get_dma_dst_pos(omap_ir->rx_dma_channel) -
+                                               omap_ir->rx_buf_dma_phys;
+
+               if (!IS_FIR(omap_ir))
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 2), omap_ir->rx_buf_dma_virt,
+                                       w - 2);
+               else
+                       /* Copy DMA buffer to skb */
+                       memcpy(skb_put(skb, w - 4), omap_ir->rx_buf_dma_virt,
+                                       w - 4);
+
+               skb->dev = dev;
+               skb_reset_mac_header(skb);
+               skb->protocol = htons(ETH_P_IRDA);
+               omap_ir->stats.rx_packets++;
+               omap_ir->stats.rx_bytes += skb->len;
+               netif_receive_skb(skb); /* Send data to upper level */
+       }
+
+       /* Re-init RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       dev->last_rx = jiffies;
+
+       return IRQ_HANDLED;
+}
+
+static int omap_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int speed = irda_get_next_speed(skb);
+       int mtt = irda_get_mtt(skb);
+       int xbofs = irda_get_next_xbofs(skb);
+
+
+       /*
+        * Does this packet contain a request to change the interface
+        * speed?  If so, remember it until we complete the transmission
+        * of this frame.
+        */
+       if (speed != omap_ir->speed && speed != -1)
+               omap_ir->newspeed = speed;
+
+       if (xbofs) /* Set number of addtional BOFS */
+               uart_reg_out(UART3_EBLR, xbofs + 1);
+
+       /*
+        * If this is an empty frame, we can bypass a lot.
+        */
+       if (skb->len == 0) {
+               if (omap_ir->newspeed) {
+                       omap_ir->newspeed = 0;
+                       omap_irda_set_speed(dev, speed);
+               }
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
+       netif_stop_queue(dev);
+
+       /* Copy skb data to DMA buffer */
+       skb_copy_from_linear_data(skb, omap_ir->tx_buf_dma_virt, skb->len);
+
+       /* Copy skb data to DMA buffer */
+       omap_ir->stats.tx_bytes += skb->len;
+
+       /* Set frame length */
+       uart_reg_out(UART3_TXFLL, (skb->len & 0xff));
+       uart_reg_out(UART3_TXFLH, (skb->len >> 8));
+
+       if (mtt > 1000)
+               mdelay(mtt / 1000);
+       else
+               udelay(mtt);
+
+       /* Start TX DMA transfer */
+       omap_start_tx_dma(omap_ir, skb->len);
+
+       /* We can free skb now because it's already in DMA buffer */
+       dev_kfree_skb(skb);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+static int
+omap_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
+{
+       struct if_irda_req *rq = (struct if_irda_req *)ifreq;
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+
+       switch (cmd) {
+       case SIOCSBANDWIDTH:
+               if (capable(CAP_NET_ADMIN)) {
+                       /*
+                        * We are unable to set the speed if the
+                        * device is not running.
+                        */
+                       if (omap_ir->open)
+                               ret = omap_irda_set_speed(dev,
+                                               rq->ifr_baudrate);
+                       else {
+                               printk(KERN_ERR "omap_ir: SIOCSBANDWIDTH:"
+                                               " !netif_running\n");
+                               ret = 0;
+                       }
+               }
+               break;
+
+       case SIOCSMEDIABUSY:
+               ret = -EPERM;
+               if (capable(CAP_NET_ADMIN)) {
+                       irda_device_set_media_busy(dev, TRUE);
+                       ret = 0;
+               }
+               break;
+
+       case SIOCGRECEIVING:
+               rq->ifr_receiving = 0;
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static struct net_device_stats *omap_irda_stats(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       return &omap_ir->stats;
+}
+
+static int omap_irda_start(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int err;
+
+       omap_ir->speed = 9600;
+
+       err = request_irq(dev->irq, omap_irda_irq, 0, dev->name, dev);
+       if (err)
+               goto err_irq;
+
+       /*
+        * The interrupt must remain disabled for now.
+        */
+       disable_irq(dev->irq);
+
+       /*  Request DMA channels for IrDA hardware */
+       if (omap_request_dma(omap_ir->pdata->rx_channel, "IrDA Rx DMA",
+                       (void *)omap_irda_rx_dma_callback,
+                       dev, &(omap_ir->rx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Rx DMA\n");
+               goto err_irq;
+       }
+
+       if (omap_request_dma(omap_ir->pdata->tx_channel, "IrDA Tx DMA",
+                       (void *)omap_irda_tx_dma_callback,
+                       dev, &(omap_ir->tx_dma_channel))) {
+               printk(KERN_ERR "Failed to request IrDA Tx DMA\n");
+               goto err_irq;
+       }
+
+       /* Allocate TX and RX buffers for DMA channels */
+       omap_ir->rx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               &(omap_ir->rx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->rx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for rx_buf_dma\n");
+               goto err_irq;
+       }
+
+       omap_ir->tx_buf_dma_virt =
+               dma_alloc_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               &(omap_ir->tx_buf_dma_phys),
+                               GFP_KERNEL);
+
+       if (!omap_ir->tx_buf_dma_virt) {
+               printk(KERN_ERR "Unable to allocate memory for tx_buf_dma\n");
+               goto err_mem1;
+       }
+
+       /*
+        * Setup the serial port for the specified config.
+        */
+       if (omap_ir->pdata->select_irda)
+               omap_ir->pdata->select_irda(omap_ir->dev, IR_SEL);
+
+       err = omap_irda_startup(dev);
+
+       if (err)
+               goto err_startup;
+
+       omap_irda_set_speed(dev, omap_ir->speed = 9600);
+
+       /*
+        * Open a new IrLAP layer instance.
+        */
+       omap_ir->irlap = irlap_open(dev, &omap_ir->qos, "omap_sir");
+
+       err = -ENOMEM;
+       if (!omap_ir->irlap)
+               goto err_irlap;
+
+       /* Now enable the interrupt and start the queue */
+       omap_ir->open = 1;
+
+       /* Start RX DMA */
+       omap_irda_start_rx_dma(omap_ir);
+
+       enable_irq(dev->irq);
+       netif_start_queue(dev);
+
+       return 0;
+
+err_irlap:
+       omap_ir->open = 0;
+       omap_irda_shutdown(omap_ir);
+err_startup:
+       dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                       omap_ir->tx_buf_dma_virt, omap_ir->tx_buf_dma_phys);
+err_mem1:
+       dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                       omap_ir->rx_buf_dma_virt, omap_ir->rx_buf_dma_phys);
+err_irq:
+       free_irq(dev->irq, dev);
+       return err;
+}
+
+static int omap_irda_stop(struct net_device *dev)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       disable_irq(dev->irq);
+
+       netif_stop_queue(dev);
+
+       omap_free_dma(omap_ir->rx_dma_channel);
+       omap_free_dma(omap_ir->tx_dma_channel);
+
+       if (omap_ir->rx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SKB_MAX_MTU,
+                               omap_ir->rx_buf_dma_virt,
+                               omap_ir->rx_buf_dma_phys);
+       if (omap_ir->tx_buf_dma_virt)
+               dma_free_coherent(NULL, IRDA_SIR_MAX_FRAME,
+                               omap_ir->tx_buf_dma_virt,
+                               omap_ir->tx_buf_dma_phys);
+
+       omap_irda_shutdown(omap_ir);
+
+       /* Stop IrLAP */
+       if (omap_ir->irlap) {
+               irlap_close(omap_ir->irlap);
+               omap_ir->irlap = NULL;
+       }
+
+       omap_ir->open = 0;
+
+       /*
+        * Free resources
+        */
+       free_irq(dev->irq, dev);
+
+       return 0;
+}
+
+static int omap_irda_set_speed(struct net_device *dev, int speed)
+{
+       struct omap_irda *omap_ir = netdev_priv(dev);
+       int divisor;
+       unsigned long flags;
+
+       /* Set IrDA speed */
+       if (speed <= 115200) {
+
+               local_irq_save(flags);
+
+               /* SIR mode */
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_SIRMODE);
+
+               /* Set SIR mode */
+               uart_reg_out(UART3_MDR1, 1);
+               uart_reg_out(UART3_EBLR, 1);
+
+               divisor = 48000000 / (16 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               uart_reg_out(UART3_MCR, 0);
+
+               local_irq_restore(flags);
+       } else if (speed <= 1152000) {
+
+               local_irq_save(flags);
+
+               /* Set MIR mode, auto SIP */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_MIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               uart_reg_out(UART3_EBLR, 2);
+
+               divisor = 48000000 / (41 * speed);      /* Base clock 48 MHz */
+
+               uart_reg_out(UART3_LCR, UART3_LCR_DIVEN);
+               uart_reg_out(UART3_DLL, (divisor & 0xff));
+               uart_reg_out(UART3_DLH, (divisor >> 8));
+               uart_reg_out(UART3_LCR, 0x03);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_MIRMODE);
+
+               local_irq_restore(flags);
+       } else {
+               local_irq_save(flags);
+
+               /* FIR mode */
+               uart_reg_out(UART3_MDR1, UART3_MDR1_FIR |
+                               UART3_MDR1_SIP_AUTO);
+
+               if (omap_ir->pdata->transceiver_mode)
+                       omap_ir->pdata->transceiver_mode(omap_ir->dev,
+                                                       IR_FIRMODE);
+
+               local_irq_restore(flags);
+       }
+
+       omap_ir->speed = speed;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the IrDA interface.
+ */
+static int omap_irda_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir = netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * Stop the transmit queue
+                */
+               netif_device_detach(dev);
+               disable_irq(dev->irq);
+               omap_irda_shutdown(omap_ir);
+       }
+       return 0;
+}
+
+/*
+ * Resume the IrDA interface.
+ */
+static int omap_irda_resume(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct omap_irda *omap_ir= netdev_priv(dev);
+
+       if (!dev)
+               return 0;
+
+       if (omap_ir->open) {
+               /*
+                * If we missed a speed change, initialise at the new speed
+                * directly.  It is debatable whether this is actually
+                * required, but in the interests of continuing from where
+                * we left off it is desireable.  The converse argument is
+                * that we should re-negotiate at 9600 baud again.
+                */
+               if (omap_ir->newspeed) {
+                       omap_ir->speed = omap_ir->newspeed;
+                       omap_ir->newspeed = 0;
+               }
+
+               omap_irda_startup(dev);
+               omap_irda_set_speed(dev, omap_ir->speed);
+               enable_irq(dev->irq);
+
+               /*
+                * This automatically wakes up the queue
+                */
+               netif_device_attach(dev);
+       }
+
+       return 0;
+}
+#else
+#define omap_irda_suspend      NULL
+#define omap_irda_resume       NULL
+#endif
+
+static int omap_irda_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct omap_irda *omap_ir;
+       struct omap_irda_config *pdata = pdev->dev.platform_data;
+       unsigned int baudrate_mask;
+       int err = 0;
+       int irq = NO_IRQ;
+
+       if (!pdata) {
+               printk(KERN_ERR "IrDA Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!pdata->rx_channel || !pdata->tx_channel) {
+               printk(KERN_ERR "IrDA invalid rx/tx channel value\n");
+               return -ENOENT;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               printk(KERN_WARNING "no irq for IrDA\n");
+               return -ENOENT;
+       }
+
+       dev = alloc_irdadev(sizeof(struct omap_irda));
+       if (!dev)
+               goto err_mem_1;
+
+
+       omap_ir = netdev_priv(dev);
+       omap_ir->dev = &pdev->dev;
+       omap_ir->pdata = pdata;
+
+       dev->hard_start_xmit    = omap_irda_hard_xmit;
+       dev->open               = omap_irda_start;
+       dev->stop               = omap_irda_stop;
+       dev->do_ioctl           = omap_irda_ioctl;
+       dev->get_stats          = omap_irda_stats;
+       dev->irq                = irq;
+
+       irda_init_max_qos_capabilies(&omap_ir->qos);
+
+       baudrate_mask = 0;
+       if (omap_ir->pdata->transceiver_cap & IR_SIRMODE)
+               baudrate_mask |= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       if (omap_ir->pdata->transceiver_cap & IR_MIRMODE)
+               baudrate_mask |= IR_57600 | IR_1152000;
+       if (omap_ir->pdata->transceiver_cap & IR_FIRMODE)
+               baudrate_mask |= IR_4000000 << 8;
+
+       omap_ir->qos.baud_rate.bits &= baudrate_mask;
+       omap_ir->qos.min_turn_time.bits = 7;
+
+       irda_qos_bits_to_value(&omap_ir->qos);
+
+       /* Any better way to avoid this? No. */
+       if (machine_is_omap_h3() || machine_is_omap_h4())
+               INIT_DELAYED_WORK(&omap_ir->pdata->gpio_expa, NULL);
+
+       err = register_netdev(dev);
+       if (!err)
+               platform_set_drvdata(pdev, dev);
+       else
+               free_netdev(dev);
+
+err_mem_1:
+       return err;
+}
+
+static int omap_irda_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       if (pdev) {
+               unregister_netdev(dev);
+               free_netdev(dev);
+       }
+       return 0;
+}
+
+static struct platform_driver omapir_driver = {
+       .probe          = omap_irda_probe,
+       .remove         = omap_irda_remove,
+       .suspend        = omap_irda_suspend,
+       .resume         = omap_irda_resume,
+       .driver         = {
+               .name   = "omapirda",
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "OMAP IrDA driver initializing\n";
+
+static int __init omap_irda_init(void)
+{
+       printk(banner);
+       return platform_driver_register(&omapir_driver);
+}
+
+static void __exit omap_irda_exit(void)
+{
+       platform_driver_unregister(&omapir_driver);
+}
+
+module_init(omap_irda_init);
+module_exit(omap_irda_exit);
+
+MODULE_AUTHOR("MontaVista");
+MODULE_DESCRIPTION("OMAP IrDA Driver");
+MODULE_LICENSE("GPL");
+
index 2abfc284519829ee05856b26b80c0ce45f2e27b5..b4d69c7310439a91a4303bc477642a5a831aebaa 100644 (file)
   #define SMC_USE_16BIT                0
   #define SMC_USE_32BIT                1
   #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+#elif defined(CONFIG_ARCH_OMAP34XX)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
+#elif defined(CONFIG_ARCH_OMAP24XX)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
 #else
 /*
  * Default configuration
index 24768c10cadb7d1e326b3651ce6819ec08021699..cebabd49e5a4f00016c3be321338ed912e6b335f 100644 (file)
@@ -448,6 +448,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 9ce55850271a17c21365dee317f43219756eff53..c0a3036cfaaaef01c22ceb260d57b2c5631773bd 100644 (file)
@@ -49,6 +49,35 @@ config BATTERY_OLPC
        help
          Say Y to enable support for the battery on the OLPC laptop.
 
+config BATTERY_BQ27x00
+       tristate "BQ27x00 battery driver"
+       help
+         Say Y here to enable support for batteries with BQ27000 or BQ27200 chip.
+
+config BATTERY_BQ27000
+       bool "BQ27000 battery driver"
+       depends on BATTERY_BQ27x00
+       select W1
+       select W1_SLAVE_BQ27000
+       help
+         Say Y here to enable support for batteries with BQ27000(HDQ) chip.
+
+config BATTERY_BQ27200
+       bool "BQ27200 battery driver"
+       depends on BATTERY_BQ27x00
+       select I2C
+       select I2C_OMAP
+       help
+         Say Y here to enable support for batteries with BQ27200(I2C) chip.
+
+config TWL4030_BCI_BATTERY
+       tristate "OMAP TWL4030 BCI Battery driver"
+       depends on (MACH_OMAP_2430SDP || MACH_OMAP_3430SDP || MACH_OMAP_LDP) && TWL4030_MADC
+       default y
+       help
+         Support for OMAP TWL4030 BCI Battery driver.
+         This driver can give support for TWL4030 Battery Charge Interface.
+
 config BATTERY_TOSA
        tristate "Sharp SL-6000 (tosa) battery"
        depends on MACH_TOSA && MFD_TC6393XB
index 4706bf8ff4595814565ebac8ee4cbb764ab91f63..8da941a8090d42d52443668c3342c09cc7aa6453 100644 (file)
@@ -20,5 +20,7 @@ obj-$(CONFIG_APM_POWER)               += apm_power.o
 obj-$(CONFIG_BATTERY_DS2760)   += ds2760_battery.o
 obj-$(CONFIG_BATTERY_PMU)      += pmu_battery.o
 obj-$(CONFIG_BATTERY_OLPC)     += olpc_battery.o
+obj-$(CONFIG_BATTERY_BQ27x00)   += bq27x00_battery.o
+obj-$(CONFIG_TWL4030_BCI_BATTERY)      += twl4030_bci_battery.o
 obj-$(CONFIG_BATTERY_TOSA)     += tosa_battery.o
 obj-$(CONFIG_BATTERY_PALMTX)   += palmtx_battery.o
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
new file mode 100644 (file)
index 0000000..8b439e8
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * linux/drivers/power/bq27x00_battery.c
+ *
+ * BQ27000/BQ27200 battery driver
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ *
+ * Author: Texas Instruments
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#ifdef CONFIG_BATTERY_BQ27000
+#include "../w1/w1.h"
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+#include <linux/i2c.h>
+#endif
+
+#define BQ27x00_REG_TEMP               0x06
+#define BQ27x00_REG_VOLT               0x08
+#define BQ27x00_REG_RSOC               0x0B /* Relative State-of-Charge */
+#define BQ27x00_REG_AI                 0x14
+#define BQ27x00_REG_FLAGS              0x0A
+#define HIGH_BYTE(A)                   ((A) << 8)
+
+#ifdef CONFIG_BATTERY_BQ27000
+extern int w1_bq27000_read(struct device *dev, u8 reg);
+#endif
+
+struct bq27x00_device_info;
+struct bq27x00_access_methods {
+       int (*read)(u8 reg, int *rt_value, int b_single,
+               struct bq27x00_device_info *di);
+};
+
+struct bq27x00_device_info {
+       struct device           *dev;
+#ifdef CONFIG_BATTERY_BQ27000
+       struct device           *w1_dev;
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+       struct i2c_client *client;
+#endif
+       unsigned long           update_time;
+       int                     voltage_uV;
+       int                     current_uA;
+       int                     temp_C;
+       int                     charge_rsoc;
+       struct bq27x00_access_methods   *bus;
+       struct power_supply     bat;
+       struct delayed_work     monitor_work;
+};
+
+static unsigned int cache_time = 60000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+
+static enum power_supply_property bq27x00_battery_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+};
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di);
+
+#ifdef CONFIG_BATTERY_BQ27000
+static int bq27000_battery_probe(struct platform_device *dev);
+static int bq27000_battery_remove(struct platform_device *dev);
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *dev,
+       pm_message_t state);
+static int bq27000_battery_resume(struct platform_device *dev);
+#endif /* CONFIG_PM */
+
+static struct platform_driver bq27000_battery_driver = {
+       .probe = bq27000_battery_probe,
+       .remove = bq27000_battery_remove,
+#ifdef CONFIG_PM
+       .suspend = bq27000_battery_suspend,
+       .resume = bq27000_battery_resume,
+#endif /* CONFIG_PM */
+       .driver = {
+               .name = "bq27000-battery",
+       },
+};
+#endif /* CONFIG_BATTERY_BQ27000 */
+
+#ifdef CONFIG_BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client);
+static int bq27200_battery_remove(struct i2c_client *client);
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client,
+               pm_message_t mesg);
+static int bq27200_battery_resume(struct i2c_client *client);
+#endif /* CONFIG_PM */
+static struct i2c_driver bq27200_battery_driver = {
+       .driver = {
+               .name   = "bq27200-bat",
+       },
+       .probe  = bq27200_battery_probe,
+       .remove = bq27200_battery_remove,
+#ifdef CONFIG_PM
+       .suspend = bq27200_battery_suspend,
+       .resume = bq27200_battery_resume,
+#endif /* CONFIG_PM */
+};
+#endif /* CONFIG_BATTERY_BQ27200 */
+
+/*
+ * Return the battery temperature in Celcius degrees
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
+{
+       int ret, temp = 0;
+
+       ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
+       if (ret) {
+               pr_err("BQ27x00 battery driver:"
+                       "Error reading temperature from the battery\n");
+               return ret;
+       }
+
+       return (temp >> 2) - 273;
+}
+
+/*
+ * Return the battery Voltage in milivolts
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
+{
+       int ret, volt = 0;
+
+       ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
+       if (ret) {
+               pr_err("BQ27x00 battery driver:"
+                       "Error reading battery voltage from the battery\n");
+               return ret;
+       }
+
+       return volt;
+}
+
+/*
+ * Return the battery average current
+ * Note that current can be negative signed as well
+ * Or 0 if something fails.
+ */
+static int bq27x00_battery_current(struct bq27x00_device_info *di)
+{
+       int ret, curr = 0, flags = 0;
+
+       ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
+       if (ret) {
+               pr_err("BQ27x00 battery driver:"
+                       "Error reading current from the battery\n");
+               return 0;
+       }
+       ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
+       if (ret < 0) {
+               pr_err("BQ27x00 battery driver:"
+                       "Error reading battery flags\n");
+               return 0;
+       }
+       if ((flags & (1 << 7)) != 0) {
+               pr_debug("Negative current\n");
+               return -curr;
+       } else {
+               return curr;
+       }
+}
+
+/*
+ * Return the battery Relative State-of-Charge
+ * Or < 0 if something fails.
+ */
+static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
+{
+       int ret, rsoc = 0;
+
+       ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
+       if (ret) {
+               pr_err("BQ27x00 battery driver:"
+                       "Error reading battery Relative"
+                       "State-of-Charge\n");
+               return ret;
+       }
+       return rsoc;
+}
+
+#ifdef CONFIG_BATTERY_BQ27000
+static inline int bq27000_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di)
+{
+       u8 val;
+
+       val = w1_bq27000_read(di->w1_dev, reg);
+       *rt_value = val;
+
+       if (!b_single) {
+               val = 0;
+               val = w1_bq27000_read(di->w1_dev, reg + 1);
+               *rt_value +=  HIGH_BYTE((int) val);
+       }
+
+       return 0;
+}
+#else
+static inline int bq27000_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di)
+{
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_BATTERY_BQ27200
+static inline int bq27200_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di)
+{
+       struct i2c_client *client = di->client;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+       int err;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       msg->addr = client->addr;
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+
+       data[0] = reg;
+       err = i2c_transfer(client->adapter, msg, 1);
+
+       if (err >= 0) {
+               if (!b_single)
+                       msg->len = 2;
+               else
+                       msg->len = 1;
+
+               msg->flags = I2C_M_RD;
+               err = i2c_transfer(client->adapter, msg, 1);
+               if (err >= 0) {
+                       if (!b_single)
+                               *rt_value = data[1] | HIGH_BYTE(data[0]);
+                       else
+                               *rt_value = data[0];
+
+                       return 0;
+               } else {
+                       pr_err("BQ27200 I2C read failed\n");
+                       return err;
+               }
+       } else {
+               pr_err("BQ27200 I2C write failed\n");
+               return err;
+       }
+}
+#else
+static inline int bq27200_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di)
+{
+       return 0;
+}
+#endif
+
+static int bq27x00_read(u8 reg, int *rt_value, int b_single,
+       struct bq27x00_device_info *di)
+{
+       int ret;
+
+       ret = di->bus->read(reg, rt_value, b_single, di);
+       return ret;
+}
+
+/*
+ * Read the battery temp, voltage, current and relative state of charge.
+ */
+static void bq27x00_battery_read_status(struct bq27x00_device_info *di)
+{
+       if (di->update_time && time_before(jiffies, di->update_time +
+                                       msecs_to_jiffies(cache_time)))
+               return;
+
+       di->temp_C = bq27x00_battery_temperature(di);
+       di->voltage_uV = bq27x00_battery_voltage(di);
+       di->current_uA = bq27x00_battery_current(di);
+       di->charge_rsoc = bq27x00_battery_rsoc(di);
+
+       di->update_time = jiffies;
+
+       return;
+}
+
+static void bq27x00_battery_work(struct delayed_work *work)
+{
+       struct bq27x00_device_info *di = container_of(work,
+               struct bq27x00_device_info, monitor_work);
+
+       bq27x00_battery_read_status(di);
+       schedule_delayed_work(&di->monitor_work, 100);
+       return;
+}
+
+#define to_bq27x00_device_info(x) container_of((x), \
+                               struct bq27x00_device_info, bat);
+
+static int bq27x00_battery_get_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       union power_supply_propval *val)
+{
+       struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = di->voltage_uV;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               val->intval = di->current_uA;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW:
+               val->intval = di->charge_rsoc;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = di->temp_C;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = di->charge_rsoc;
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               if (di->voltage_uV == 0)
+                       val->intval = 0;
+               else
+                       val->intval = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
+{
+       di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+       di->bat.properties = bq27x00_battery_props;
+       di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
+       di->bat.get_property = bq27x00_battery_get_property;
+       di->bat.external_power_changed = NULL;
+       return;
+}
+
+#ifdef CONFIG_BATTERY_BQ27200
+static int bq27200_battery_probe(struct i2c_client *client)
+{
+       struct bq27x00_device_info *di;
+       struct bq27x00_access_methods *bus;
+       int retval = 0;
+
+       di = kzalloc(sizeof(*di), GFP_KERNEL);
+       if (!di) {
+               pr_err("BQ27000 battery driver:"
+                       "Failed to allocate device info structure\n");
+               return -ENOMEM;
+       }
+
+       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+       if (!bus) {
+               pr_err("BQ27000 battery driver:"
+                       "Failed to allocate access method structure\n");
+               kfree(di);
+               return -ENOMEM;
+       }
+
+       i2c_set_clientdata(client, di);
+       di->dev = &client->dev;
+       di->bat.name = "bq27200";
+       bus->read = &bq27200_read;
+       di->bus = bus;
+       di->client = client;
+
+       bq27x00_powersupply_init(di);
+
+       retval = power_supply_register(&client->dev, &di->bat);
+       if (retval) {
+               pr_err("BQ27200 battery driver: Failed to register battery\n");
+               goto batt_failed;
+       }
+
+       INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+       schedule_delayed_work(&di->monitor_work, 100);
+
+       return 0;
+
+batt_failed:
+       kfree(bus);
+       kfree(di);
+       return retval;
+}
+
+static int bq27200_battery_remove(struct i2c_client *client)
+{
+       struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+       flush_scheduled_work();
+       power_supply_unregister(&di->bat);
+       kfree(di);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27200_battery_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+       cancel_delayed_work(&di->monitor_work);
+       return 0;
+}
+
+static int bq27200_battery_resume(struct i2c_client *client)
+{
+       struct bq27x00_device_info *di  = i2c_get_clientdata(client);
+
+       schedule_delayed_work(&di->monitor_work, 0);
+       return 0;
+}
+#endif /* CONFIG_PM */
+#endif /* CONFIG_BATTERY_BQ27200 */
+
+#ifdef CONFIG_BATTERY_BQ27000
+static int bq27000_battery_probe(struct  platform_device *pdev)
+{
+       struct bq27x00_device_info *di;
+       struct bq27x00_access_methods *bus;
+       int retval = 0;
+
+       di = kzalloc(sizeof(*di), GFP_KERNEL);
+       if (!di) {
+               pr_err("BQ27000 battery driver:"
+                       "Failed to allocate device info structure\n");
+               return -ENOMEM;
+       }
+
+       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+       if (!bus) {
+               pr_err("BQ27000 battery driver:"
+                       "Failed to allocate access method structure\n");
+               kfree(di);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, di);
+
+       di->dev = &pdev->dev;
+       di->w1_dev = pdev->dev.parent;
+       di->bat.name = "bq27000";
+       bus->read = &bq27000_read;
+       di->bus = bus;
+
+       bq27x00_powersupply_init(di);
+
+       retval = power_supply_register(&pdev->dev, &di->bat);
+       if (retval) {
+               pr_err("BQ27000 battery driver: Failed to register battery\n");
+               goto batt_failed;
+       }
+
+       INIT_DELAYED_WORK(&di->monitor_work, bq27x00_battery_work);
+       schedule_delayed_work(&di->monitor_work, 50);
+
+       return 0;
+
+batt_failed:
+       kfree(bus);
+       kfree(di);
+       return retval;
+}
+
+static int bq27000_battery_remove(struct  platform_device *pdev)
+{
+       struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+       flush_scheduled_work();
+       power_supply_unregister(&di->bat);
+       platform_set_drvdata(pdev, NULL);
+       kfree(di);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int bq27000_battery_suspend(struct platform_device *pdev,
+       pm_message_t state)
+{
+       struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+       cancel_delayed_work(&di->monitor_work);
+       return 0;
+}
+
+static int bq27000_battery_resume(struct platform_device *pdev)
+{
+       struct bq27x00_device_info *di = platform_get_drvdata(pdev);
+
+       schedule_delayed_work(&di->monitor_work, 0);
+       return 0;
+}
+#endif /* CONFIG_PM */
+#endif /* CONFIG_BATTERY_BQ27000 */
+
+static int __init bq27x00_battery_init(void)
+{
+       int status = 0;
+
+#ifdef CONFIG_BATTERY_BQ27000
+       status = platform_driver_register(&bq27000_battery_driver);
+       if (status)
+               printk(KERN_ERR "Unable to register BQ27000 driver\n");
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+       status = i2c_add_driver(&bq27200_battery_driver);
+               printk(KERN_ERR "Unable to register BQ27200 driver\n");
+#endif
+       return status;
+}
+
+static void __exit bq27x00_battery_exit(void)
+{
+#ifdef CONFIG_BATTERY_BQ27000
+       platform_driver_unregister(&bq27000_battery_driver);
+#endif
+#ifdef CONFIG_BATTERY_BQ27200
+       i2c_del_driver(&bq27200_battery_driver);
+#endif
+}
+
+module_init(bq27x00_battery_init);
+module_exit(bq27x00_battery_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("BQ27x00 battery moniter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/twl4030_bci_battery.c b/drivers/power/twl4030_bci_battery.c
new file mode 100644 (file)
index 0000000..a36eaae
--- /dev/null
@@ -0,0 +1,1093 @@
+/*
+ * linux/drivers/power/twl4030_bci_battery.c
+ *
+ * OMAP2430/3430 BCI battery driver for Linux
+ *
+ * Copyright (C) 2008 Texas Instruments, Inc.
+ * Author: Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/power_supply.h>
+#include <linux/i2c/twl4030-madc.h>
+
+#define T2_BATTERY_VOLT                0x04
+#define T2_BATTERY_TEMP                0x06
+#define T2_BATTERY_CUR         0x08
+
+/* charger constants */
+#define NO_PW_CONN             0
+#define AC_PW_CONN             0x01
+#define USB_PW_CONN            0x02
+
+/* TWL4030_MODULE_USB */
+#define REG_POWER_CTRL         0x0AC
+#define OTG_EN                 0x020
+#define REG_PHY_CLK_CTRL       0x0FE
+#define REG_PHY_CLK_CTRL_STS   0x0FF
+#define PHY_DPLL_CLK           0x01
+
+#define REG_BCICTL1            0x023
+#define REG_BCICTL2            0x024
+#define CGAIN                  0x020
+#define ITHEN                  0x010
+#define ITHSENS                        0x007
+
+/* Boot BCI flag bits */
+#define BCIAUTOWEN             0x020
+#define CONFIG_DONE            0x010
+#define BCIAUTOUSB             0x002
+#define BCIAUTOAC              0x001
+#define BCIMSTAT_MASK          0x03F
+
+/* Boot BCI register */
+#define REG_BOOT_BCI           0x007
+#define REG_CTRL1              0x00
+#define REG_SW1SELECT_MSB      0x07
+#define SW1_CH9_SEL            0x02
+#define REG_CTRL_SW1           0x012
+#define SW1_TRIGGER            0x020
+#define EOC_SW1                        0x002
+#define REG_GPCH9              0x049
+#define REG_STS_HW_CONDITIONS  0x0F
+#define STS_VBUS               0x080
+#define STS_CHG                        0x02
+#define REG_BCIMSTATEC         0x02
+#define REG_BCIMFSTS4          0x010
+#define REG_BCIMFSTS2          0x00E
+#define REG_BCIMFSTS3          0x00F
+#define REG_BCIMFSTS1          0x001
+#define USBFASTMCHG            0x004
+#define BATSTSPCHG             0x004
+#define BATSTSMCHG             0x040
+#define VBATOV4                        0x020
+#define VBATOV3                        0x010
+#define VBATOV2                        0x008
+#define VBATOV1                        0x004
+#define REG_BB_CFG             0x012
+#define BBCHEN                 0x010
+
+/* Power supply charge interrupt */
+#define REG_PWR_ISR1           0x00
+#define REG_PWR_IMR1           0x01
+#define REG_PWR_EDR1           0x05
+#define REG_PWR_SIH_CTRL       0x007
+
+#define USB_PRES               0x004
+#define CHG_PRES               0x002
+
+#define USB_PRES_RISING                0x020
+#define USB_PRES_FALLING       0x010
+#define CHG_PRES_RISING                0x008
+#define CHG_PRES_FALLING       0x004
+#define AC_STATEC              0x20
+#define COR                    0x004
+
+/* interrupt status registers */
+#define REG_BCIISR1A           0x0
+#define REG_BCIISR2A           0x01
+
+/* Interrupt flags bits BCIISR1 */
+#define BATSTS_ISR1            0x080
+#define VBATLVL_ISR1           0x001
+
+/* Interrupt mask registers for int1*/
+#define REG_BCIIMR1A           0x002
+#define REG_BCIIMR2A           0x003
+
+ /* Interrupt masks for BCIIMR1 */
+#define BATSTS_IMR1            0x080
+#define VBATLVL_IMR1           0x001
+
+/* Interrupt edge detection register */
+#define REG_BCIEDR1            0x00A
+#define REG_BCIEDR2            0x00B
+#define REG_BCIEDR3            0x00C
+
+/* BCIEDR2 */
+#define        BATSTS_EDRRISIN         0x080
+#define BATSTS_EDRFALLING      0x040
+
+/* BCIEDR3 */
+#define        VBATLVL_EDRRISIN        0x02
+
+/* Step size and prescaler ratio */
+#define TEMP_STEP_SIZE         147
+#define TEMP_PSR_R             100
+
+#define VOLT_STEP_SIZE         588
+#define VOLT_PSR_R             100
+
+#define CURR_STEP_SIZE         147
+#define CURR_PSR_R1            44
+#define CURR_PSR_R2            80
+
+#define BK_VOLT_STEP_SIZE      441
+#define BK_VOLT_PSR_R          100
+
+#define ENABLE         1
+#define DISABLE                1
+
+/* Ptr to thermistor table */
+int *therm_tbl;
+
+struct twl4030_bci_device_info {
+       struct device           *dev;
+
+       unsigned long           update_time;
+       int                     voltage_uV;
+       int                     bk_voltage_uV;
+       int                     current_uA;
+       int                     temp_C;
+       int                     charge_rsoc;
+       int                     charge_status;
+
+       struct power_supply     bat;
+       struct power_supply     bk_bat;
+       struct delayed_work     twl4030_bci_monitor_work;
+       struct delayed_work     twl4030_bk_bci_monitor_work;
+};
+
+static int usb_charger_flag;
+static int LVL_1, LVL_2, LVL_3, LVL_4;
+
+static int read_bci_val(u8 reg_1);
+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg);
+static int twl4030charger_presence(void);
+
+/*
+ * Report and clear the charger presence event.
+ */
+static inline int twl4030charger_presence_evt(void)
+{
+       int ret;
+       u8 chg_sts, set = 0, clear = 0;
+
+       /* read charger power supply status */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
+               REG_STS_HW_CONDITIONS);
+       if (ret)
+               return IRQ_NONE;
+
+       if (chg_sts & STS_CHG) { /* If the AC charger have been connected */
+               /* configuring falling edge detection for CHG_PRES */
+               set = CHG_PRES_FALLING;
+               clear = CHG_PRES_RISING;
+       } else { /* If the AC charger have been disconnected */
+               /* configuring rising edge detection for CHG_PRES */
+               set = CHG_PRES_RISING;
+               clear = CHG_PRES_FALLING;
+       }
+
+       /* Update the interrupt edge detection register */
+       clear_n_set(TWL4030_MODULE_INT, clear, set, REG_PWR_EDR1);
+
+       return 0;
+}
+
+/*
+ * Interrupt service routine
+ *
+ * Attends to TWL 4030 power module interruptions events, specifically
+ * USB_PRES (USB charger presence) CHG_PRES (AC charger presence) events
+ *
+ */
+static irqreturn_t twl4030charger_interrupt(int irq, void *_di)
+{
+       struct twl4030_bci_device_info *di = _di;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       twl4030charger_presence_evt();
+       power_supply_changed(&di->bat);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * This function handles the twl4030 battery presence interrupt
+ */
+static int twl4030battery_presence_evt(void)
+{
+       int ret;
+       u8 batstsmchg, batstspchg;
+
+       /* check for the battery presence in main charge*/
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                       &batstsmchg, REG_BCIMFSTS3);
+       if (ret)
+               return ret;
+
+       /* check for the battery presence in precharge */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_PRECHARGE,
+                       &batstspchg, REG_BCIMFSTS1);
+       if (ret)
+               return ret;
+
+       /*
+        * REVISIT: Physically inserting/removing the batt
+        * does not seem to generate an int on 3430ES2 SDP.
+        */
+       if ((batstspchg & BATSTSPCHG) || (batstsmchg & BATSTSMCHG)) {
+               /* In case of the battery insertion event */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRRISIN,
+                       BATSTS_EDRFALLING, REG_BCIEDR2);
+               if (ret)
+                       return ret;
+       } else {
+               /* In case of the battery removal event */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_EDRFALLING,
+                       BATSTS_EDRRISIN, REG_BCIEDR2);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * This function handles the twl4030 battery voltage level interrupt.
+ */
+static int twl4030battery_level_evt(void)
+{
+       int ret;
+       u8 mfst;
+
+       /* checking for threshold event */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+                       &mfst, REG_BCIMFSTS2);
+       if (ret)
+               return ret;
+
+       /* REVISIT could use a bitmap */
+       if (mfst & VBATOV4) {
+               LVL_4 = 1;
+               LVL_3 = 0;
+               LVL_2 = 0;
+               LVL_1 = 0;
+       } else if (mfst & VBATOV3) {
+               LVL_4 = 0;
+               LVL_3 = 1;
+               LVL_2 = 0;
+               LVL_1 = 0;
+       } else if (mfst & VBATOV2) {
+               LVL_4 = 0;
+               LVL_3 = 0;
+               LVL_2 = 1;
+               LVL_1 = 0;
+       } else {
+               LVL_4 = 0;
+               LVL_3 = 0;
+               LVL_2 = 0;
+               LVL_1 = 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Interrupt service routine
+ *
+ * Attends to BCI interruptions events,
+ * specifically BATSTS (battery connection and removal)
+ * VBATOV (main battery voltage threshold) events
+ *
+ */
+static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
+{
+       u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
+       int ret;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate.  Although it might be
+        * friendlier not to borrow this thread context...
+        */
+       local_irq_enable();
+#endif
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr1a_val,
+                               REG_BCIISR1A);
+       if (ret)
+               return IRQ_NONE;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_INTERRUPTS, &isr2a_val,
+                               REG_BCIISR2A);
+       if (ret)
+               return IRQ_NONE;
+
+       clear_2a = (isr2a_val & VBATLVL_ISR1) ? (VBATLVL_ISR1) : 0;
+       clear_1a = (isr1a_val & BATSTS_ISR1) ? (BATSTS_ISR1) : 0;
+
+       /* cleaning BCI interrupt status flags */
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
+                       clear_1a , REG_BCIISR1A);
+       if (ret)
+               return IRQ_NONE;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS,
+                       clear_2a , REG_BCIISR2A);
+       if (ret)
+               return IRQ_NONE;
+
+       /* battery connetion or removal event */
+       if (isr1a_val & BATSTS_ISR1)
+               twl4030battery_presence_evt();
+       /* battery voltage threshold event*/
+       else if (isr2a_val & VBATLVL_ISR1)
+               twl4030battery_level_evt();
+       else
+               return IRQ_NONE;
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Enable/Disable hardware battery level event notifications.
+ */
+static int twl4030battery_hw_level_en(int enable)
+{
+       int ret;
+
+       if (enable) {
+               /* unmask VBATOV interrupt for INT1 */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, VBATLVL_IMR1,
+                       0, REG_BCIIMR2A);
+               if (ret)
+                       return ret;
+
+               /* configuring interrupt edge detection for VBATOv */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+                       VBATLVL_EDRRISIN, REG_BCIEDR3);
+               if (ret)
+                       return ret;
+       } else {
+               /* mask VBATOV interrupt for INT1 */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+                       VBATLVL_IMR1, REG_BCIIMR2A);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Enable/disable hardware battery presence event notifications.
+ */
+static int twl4030battery_hw_presence_en(int enable)
+{
+       int ret;
+
+       if (enable) {
+               /* unmask BATSTS interrupt for INT1 */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, BATSTS_IMR1,
+                       0, REG_BCIIMR1A);
+               if (ret)
+                       return ret;
+
+               /* configuring interrupt edge for BATSTS */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+                       BATSTS_EDRRISIN | BATSTS_EDRFALLING, REG_BCIEDR2);
+               if (ret)
+                       return ret;
+       } else {
+               /* mask BATSTS interrupt for INT1 */
+               ret = clear_n_set(TWL4030_MODULE_INTERRUPTS, 0,
+                       BATSTS_IMR1, REG_BCIIMR1A);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Enable/Disable AC Charge funtionality.
+ */
+static int twl4030charger_ac_en(int enable)
+{
+       int ret;
+
+       if (enable) {
+               /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 1 */
+               ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
+                       (CONFIG_DONE | BCIAUTOWEN | BCIAUTOAC),
+                       REG_BOOT_BCI);
+               if (ret)
+                       return ret;
+       } else {
+               /* forcing the field BCIAUTOAC (BOOT_BCI[0) to 0*/
+               ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOAC,
+                       (CONFIG_DONE | BCIAUTOWEN),
+                       REG_BOOT_BCI);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Enable/Disable USB Charge funtionality.
+ */
+int twl4030charger_usb_en(int enable)
+{
+       u8 value;
+       int ret;
+       unsigned long timeout;
+
+       if (enable) {
+               /* Check for USB charger conneted */
+               ret = twl4030charger_presence();
+               if (ret < 0)
+                       return ret;
+
+               if (!(ret & USB_PW_CONN))
+                       return -ENXIO;
+
+               /* forcing the field BCIAUTOUSB (BOOT_BCI[1]) to 1 */
+               ret = clear_n_set(TWL4030_MODULE_PM_MASTER, 0,
+                       (CONFIG_DONE | BCIAUTOWEN | BCIAUTOUSB),
+                       REG_BOOT_BCI);
+               if (ret)
+                       return ret;
+
+               ret = clear_n_set(TWL4030_MODULE_USB, 0, PHY_DPLL_CLK,
+                       REG_PHY_CLK_CTRL);
+               if (ret)
+                       return ret;
+
+               value = 0;
+               timeout = jiffies + msecs_to_jiffies(50);
+
+               while ((!(value & PHY_DPLL_CLK)) &&
+                       time_before(jiffies, timeout)) {
+                       udelay(10);
+                       ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &value,
+                               REG_PHY_CLK_CTRL_STS);
+                       if (ret)
+                               return ret;
+               }
+
+               /* OTG_EN (POWER_CTRL[5]) to 1 */
+               ret = clear_n_set(TWL4030_MODULE_USB, 0, OTG_EN,
+                       REG_POWER_CTRL);
+               if (ret)
+                       return ret;
+
+               mdelay(50);
+
+               /* forcing USBFASTMCHG(BCIMFSTS4[2]) to 1 */
+               ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0,
+                       USBFASTMCHG, REG_BCIMFSTS4);
+               if (ret)
+                       return ret;
+       } else {
+               twl4030charger_presence();
+               ret = clear_n_set(TWL4030_MODULE_PM_MASTER, BCIAUTOUSB,
+                       (CONFIG_DONE | BCIAUTOWEN), REG_BOOT_BCI);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Return battery temperature
+ * Or < 0 on failure.
+ */
+static int twl4030battery_temperature(void)
+{
+       u8 val;
+       int temp, curr, volt, res, ret;
+
+       /* Getting and calculating the thermistor voltage */
+       ret = read_bci_val(T2_BATTERY_TEMP);
+       if (ret < 0)
+               return ret;
+
+       volt = (ret * TEMP_STEP_SIZE) / TEMP_PSR_R;
+
+       /* Getting and calculating the supply current in micro ampers */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+                REG_BCICTL2);
+       if (ret)
+               return 0;
+
+       curr = ((val & ITHSENS) + 1) * 10;
+
+       /* Getting and calculating the thermistor resistance in ohms*/
+       res = volt * 1000 / curr;
+
+       /*calculating temperature*/
+       for (temp = 58; temp >= 0; temp--) {
+               int actual = therm_tbl[temp];
+               if ((actual - res) >= 0)
+                       break;
+       }
+
+       /* Negative temperature */
+       if (temp < 3) {
+               if (temp == 2)
+                       temp = -1;
+               else if (temp == 1)
+                       temp = -2;
+               else
+                       temp = -3;
+       }
+
+       return temp + 1;
+}
+
+/*
+ * Return battery voltage
+ * Or < 0 on failure.
+ */
+static int twl4030battery_voltage(void)
+{
+       int volt = read_bci_val(T2_BATTERY_VOLT);
+
+       return (volt * VOLT_STEP_SIZE) / VOLT_PSR_R;
+}
+
+/*
+ * Return the battery current
+ * Or < 0 on failure.
+ */
+static int twl4030battery_current(void)
+{
+       int ret, curr = read_bci_val(T2_BATTERY_CUR);
+       u8 val;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+               REG_BCICTL1);
+       if (ret)
+               return ret;
+
+       if (val & CGAIN) /* slope of 0.44 mV/mA */
+               return (curr * CURR_STEP_SIZE) / CURR_PSR_R1;
+       else /* slope of 0.88 mV/mA */
+               return (curr * CURR_STEP_SIZE) / CURR_PSR_R2;
+}
+
+/*
+ * Return the battery backup voltage
+ * Or < 0 on failure.
+ */
+static int twl4030backupbatt_voltage(void)
+{
+       struct twl4030_madc_request req;
+       int temp;
+
+       req.channels = (1 << 9);
+       req.do_avg = 0;
+       req.method = TWL4030_MADC_SW1;
+       req.active = 0;
+       req.func_cb = NULL;
+       twl4030_madc_conversion(&req);
+       temp = (u16)req.rbuf[9];
+
+       return  (temp * BK_VOLT_STEP_SIZE) / BK_VOLT_PSR_R;
+}
+
+/*
+ * Returns an integer value, that means,
+ * NO_PW_CONN  no power supply is connected
+ * AC_PW_CONN  if the AC power supply is connected
+ * USB_PW_CONN  if the USB power supply is connected
+ * AC_PW_CONN + USB_PW_CONN if USB and AC power supplies are both connected
+ *
+ * Or < 0 on failure.
+ */
+static int twl4030charger_presence(void)
+{
+       int ret;
+       u8 hwsts;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
+               REG_STS_HW_CONDITIONS);
+       if (ret) {
+               pr_err("twl4030_bci: error reading STS_HW_CONDITIONS\n");
+               return ret;
+       }
+
+       ret = (hwsts & STS_CHG) ? AC_PW_CONN : NO_PW_CONN;
+       ret += (hwsts & STS_VBUS) ? USB_PW_CONN : NO_PW_CONN;
+
+       if (ret & USB_PW_CONN)
+               usb_charger_flag = 1;
+       else
+               usb_charger_flag = 0;
+
+       return ret;
+
+}
+
+/*
+ * Returns the main charge FSM status
+ * Or < 0 on failure.
+ */
+static int twl4030bci_status(void)
+{
+       int ret;
+       u8 status;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
+               &status, REG_BCIMSTATEC);
+       if (ret) {
+               pr_err("twl4030_bci: error reading BCIMSTATEC\n");
+               return ret;
+       }
+
+       return (int) (status & BCIMSTAT_MASK);
+}
+
+static int read_bci_val(u8 reg)
+{
+       int ret, temp;
+       u8 val;
+
+       /* reading MSB */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+               reg + 1);
+       if (ret)
+               return ret;
+
+       temp = ((int)(val & 0x03)) << 8;
+
+       /* reading LSB */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
+               reg);
+       if (ret)
+               return ret;
+
+       return temp | val;
+}
+
+/*
+ * Settup the twl4030 BCI module to enable backup
+ * battery charging.
+ */
+static int twl4030backupbatt_voltage_setup(void)
+{
+       int ret;
+
+       /* Starting backup batery charge */
+       ret = clear_n_set(TWL4030_MODULE_PM_RECEIVER, 0, BBCHEN,
+               REG_BB_CFG);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * Settup the twl4030 BCI module to measure battery
+ * temperature
+ */
+static int twl4030battery_temp_setup(void)
+{
+       int ret;
+
+       /* Enabling thermistor current */
+       ret = clear_n_set(TWL4030_MODULE_MAIN_CHARGE, 0, ITHEN,
+               REG_BCICTL1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * Sets and clears bits on an given register on a given module
+ */
+static inline int clear_n_set(u8 mod_no, u8 clear, u8 set, u8 reg)
+{
+       int ret;
+       u8 val = 0;
+
+       /* Gets the initial register value */
+       ret = twl4030_i2c_read_u8(mod_no, &val, reg);
+       if (ret)
+               return ret;
+
+       /* Clearing all those bits to clear */
+       val &= ~(clear);
+
+       /* Setting all those bits to set */
+       val |= set;
+
+       /* Update the register */
+       ret = twl4030_i2c_write_u8(mod_no, val, reg);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static enum power_supply_property twl4030_bci_battery_props[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_TEMP,
+};
+
+static enum power_supply_property twl4030_bk_bci_battery_props[] = {
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+static void
+twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
+{
+       di->bk_voltage_uV = twl4030backupbatt_voltage();
+}
+
+static void twl4030_bk_bci_battery_work(struct work_struct *work)
+{
+       struct twl4030_bci_device_info *di = container_of(work,
+               struct twl4030_bci_device_info,
+               twl4030_bk_bci_monitor_work.work);
+
+       twl4030_bk_bci_battery_read_status(di);
+       schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+}
+
+static void twl4030_bci_battery_read_status(struct twl4030_bci_device_info *di)
+{
+       di->temp_C = twl4030battery_temperature();
+       di->voltage_uV = twl4030battery_voltage();
+       di->current_uA = twl4030battery_current();
+}
+
+static void
+twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
+{
+       twl4030_bci_battery_read_status(di);
+       di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+       if (power_supply_am_i_supplied(&di->bat))
+               di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
+       else
+               di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+}
+
+static void twl4030_bci_battery_work(struct work_struct *work)
+{
+       struct twl4030_bci_device_info *di = container_of(work,
+               struct twl4030_bci_device_info, twl4030_bci_monitor_work.work);
+
+       twl4030_bci_battery_update_status(di);
+       schedule_delayed_work(&di->twl4030_bci_monitor_work, 100);
+}
+
+
+#define to_twl4030_bci_device_info(x) container_of((x), \
+                       struct twl4030_bci_device_info, bat);
+
+static void twl4030_bci_battery_external_power_changed(struct power_supply *psy)
+{
+       struct twl4030_bci_device_info *di = to_twl4030_bci_device_info(psy);
+
+       cancel_delayed_work(&di->twl4030_bci_monitor_work);
+       schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+}
+
+#define to_twl4030_bk_bci_device_info(x) container_of((x), \
+               struct twl4030_bci_device_info, bk_bat);
+
+static int twl4030_bk_bci_battery_get_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       union power_supply_propval *val)
+{
+       struct twl4030_bci_device_info *di = to_twl4030_bk_bci_device_info(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = di->bk_voltage_uV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int twl4030_bci_battery_get_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       union power_supply_propval *val)
+{
+       struct twl4030_bci_device_info *di;
+       int status = 0;
+
+       di = to_twl4030_bci_device_info(psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               val->intval = di->charge_status;
+               return 0;
+       default:
+               break;
+       }
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = di->voltage_uV;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               val->intval = di->current_uA;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = di->temp_C;
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               status = twl4030bci_status();
+               if ((status & AC_STATEC) == AC_STATEC)
+                       val->intval = POWER_SUPPLY_TYPE_MAINS;
+               else if (usb_charger_flag)
+                       val->intval = POWER_SUPPLY_TYPE_USB;
+               else
+                       val->intval = 0;
+               break;
+       case POWER_SUPPLY_PROP_CAPACITY:
+               /*
+                * need to get the correct percentage value per the
+                * battery characteristics. Approx values for now.
+                */
+               if (di->voltage_uV < 2894 || LVL_1) {
+                       val->intval = 5;
+                       LVL_1 = 0;
+               } else if ((di->voltage_uV < 3451 && di->voltage_uV > 2894)
+                       || LVL_2) {
+                       val->intval = 20;
+                       LVL_2 = 0;
+               } else if ((di->voltage_uV < 3902 && di->voltage_uV > 3451)
+                       || LVL_3) {
+                       val->intval = 50;
+                       LVL_3 = 0;
+               } else if ((di->voltage_uV < 3949 && di->voltage_uV > 3902)
+                       || LVL_4) {
+                       val->intval = 75;
+                       LVL_4 = 0;
+               } else if (di->voltage_uV > 3949)
+                       val->intval = 90;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static char *twl4030_bci_supplied_to[] = {
+       "twl4030_bci_battery",
+};
+
+static int __init twl4030_bci_battery_probe(struct platform_device *pdev)
+{
+       struct twl4030_bci_platform_data *pdata = pdev->dev.platform_data;
+       struct twl4030_bci_device_info *di;
+       int irq;
+       int ret;
+
+       therm_tbl = pdata->battery_tmp_tbl;
+
+       di = kzalloc(sizeof(*di), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->dev = &pdev->dev;
+       di->bat.name = "twl4030_bci_battery";
+       di->bat.supplied_to = twl4030_bci_supplied_to;
+       di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
+       di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+       di->bat.properties = twl4030_bci_battery_props;
+       di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
+       di->bat.get_property = twl4030_bci_battery_get_property;
+       di->bat.external_power_changed =
+                       twl4030_bci_battery_external_power_changed;
+
+       di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+
+       di->bk_bat.name = "twl4030_bci_bk_battery";
+       di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
+       di->bk_bat.properties = twl4030_bk_bci_battery_props;
+       di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
+       di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
+       di->bk_bat.external_power_changed = NULL;
+
+       twl4030charger_ac_en(ENABLE);
+       twl4030charger_usb_en(ENABLE);
+       twl4030battery_hw_level_en(ENABLE);
+       twl4030battery_hw_presence_en(ENABLE);
+
+       platform_set_drvdata(pdev, di);
+
+       /* settings for temperature sensing */
+       ret = twl4030battery_temp_setup();
+       if (ret)
+               goto temp_setup_fail;
+
+       /* enabling GPCH09 for read back battery voltage */
+       ret = twl4030backupbatt_voltage_setup();
+       if (ret)
+               goto voltage_setup_fail;
+
+       /* REVISIT do we need to request both IRQs ?? */
+
+       /* request BCI interruption */
+       ret = request_irq(TWL4030_MODIRQ_BCI, twl4030battery_interrupt,
+               0, pdev->name, NULL);
+       if (ret) {
+               dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+                       TWL4030_MODIRQ_BCI, ret);
+               goto batt_irq_fail;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+
+       /* request Power interruption */
+       ret = request_irq(irq, twl4030charger_interrupt,
+               0, pdev->name, di);
+
+       if (ret) {
+               dev_dbg(&pdev->dev, "could not request irq %d, status %d\n",
+                       irq, ret);
+               goto chg_irq_fail;
+       }
+
+       ret = power_supply_register(&pdev->dev, &di->bat);
+       if (ret) {
+               dev_dbg(&pdev->dev, "failed to register main battery\n");
+               goto batt_failed;
+       }
+
+       INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
+                               twl4030_bci_battery_work);
+       schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+
+       ret = power_supply_register(&pdev->dev, &di->bk_bat);
+       if (ret) {
+               dev_dbg(&pdev->dev, "failed to register backup battery\n");
+               goto bk_batt_failed;
+       }
+
+       INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
+                               twl4030_bk_bci_battery_work);
+       schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
+
+       return 0;
+
+bk_batt_failed:
+       power_supply_unregister(&di->bat);
+batt_failed:
+       free_irq(irq, di);
+chg_irq_fail:
+       free_irq(TWL4030_MODIRQ_BCI, NULL);
+batt_irq_fail:
+voltage_setup_fail:
+temp_setup_fail:
+       twl4030charger_ac_en(DISABLE);
+       twl4030charger_usb_en(DISABLE);
+       twl4030battery_hw_level_en(DISABLE);
+       twl4030battery_hw_presence_en(DISABLE);
+       kfree(di);
+
+       return ret;
+}
+
+static int __exit twl4030_bci_battery_remove(struct platform_device *pdev)
+{
+       struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       twl4030charger_ac_en(DISABLE);
+       twl4030charger_usb_en(DISABLE);
+       twl4030battery_hw_level_en(DISABLE);
+       twl4030battery_hw_presence_en(DISABLE);
+
+       free_irq(TWL4030_MODIRQ_BCI, NULL);
+       free_irq(irq, di);
+
+       flush_scheduled_work();
+       power_supply_unregister(&di->bat);
+       power_supply_unregister(&di->bk_bat);
+       platform_set_drvdata(pdev, NULL);
+       kfree(di);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int twl4030_bci_battery_suspend(struct platform_device *pdev,
+       pm_message_t state)
+{
+       struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+
+       di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
+       cancel_delayed_work(&di->twl4030_bci_monitor_work);
+       cancel_delayed_work(&di->twl4030_bk_bci_monitor_work);
+       return 0;
+}
+
+static int twl4030_bci_battery_resume(struct platform_device *pdev)
+{
+       struct twl4030_bci_device_info *di = platform_get_drvdata(pdev);
+
+       schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);
+       schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 50);
+       return 0;
+}
+#else
+#define twl4030_bci_battery_suspend    NULL
+#define twl4030_bci_battery_resume     NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver twl4030_bci_battery_driver = {
+       .probe          = twl4030_bci_battery_probe,
+       .remove         = __exit_p(twl4030_bci_battery_remove),
+       .suspend        = twl4030_bci_battery_suspend,
+       .resume         = twl4030_bci_battery_resume,
+       .driver         = {
+               .name   = "twl4030_bci",
+       },
+};
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_bci");
+MODULE_AUTHOR("Texas Instruments Inc");
+
+static int __init twl4030_battery_init(void)
+{
+       return platform_driver_register(&twl4030_bci_battery_driver);
+}
+module_init(twl4030_battery_init);
+
+static void __exit twl4030_battery_exit(void)
+{
+       platform_driver_unregister(&twl4030_bci_battery_driver);
+}
+module_exit(twl4030_battery_exit);
+
index 9a9755c92fada3268f03f69ee7270964bf322818..bcc0d9658121a4158fe587537c00fa742dbea93a 100644 (file)
@@ -246,6 +246,16 @@ config RTC_DRV_TWL92330
          platforms.  The support is integrated with the rest of
          the Menelaus driver; it's not separate module.
 
+config RTC_DRV_TWL4030
+       tristate "OMAP TWL4030 Real Time Clock"
+       depends on RTC_CLASS && TWL4030_CORE
+       help
+         If you say yes here you get support for internal Real-Time 
+         Clock of TWL4030 chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-twl4030.
+
 config RTC_DRV_S35390A
        tristate "Seiko Instruments S-35390A"
        select BITREVERSE
index 18622ef84cab0c4f48e15aa437edccff357136e4..3ef1dfcc90382e6c3ba6b5669c4788d7641b53af 100644 (file)
@@ -56,6 +56,7 @@ obj-$(CONFIG_RTC_DRV_SA1100)  += rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_SH)       += rtc-sh.o
 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl4030.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
new file mode 100644 (file)
index 0000000..53c67c6
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * rtc-twl4030.c -- TWL4030 Real Time Clock interface
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc
+ * Author: Alexandre Rusev <source@mvista.com>
+ *
+ * Based on original TI driver twl4030-rtc.c
+ *   Copyright (C) 2006 Texas Instruments, Inc.
+ *
+ * Based on rtc-omap.c
+ *   Copyright (C) 2003 MontaVista Software, Inc.
+ *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *   Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c/twl4030.h>
+
+
+/*
+ * RTC block register offsets (use TWL_MODULE_RTC)
+ */
+#define REG_SECONDS_REG                          0x00
+#define REG_MINUTES_REG                          0x01
+#define REG_HOURS_REG                            0x02
+#define REG_DAYS_REG                             0x03
+#define REG_MONTHS_REG                           0x04
+#define REG_YEARS_REG                            0x05
+#define REG_WEEKS_REG                            0x06
+
+#define REG_ALARM_SECONDS_REG                    0x07
+#define REG_ALARM_MINUTES_REG                    0x08
+#define REG_ALARM_HOURS_REG                      0x09
+#define REG_ALARM_DAYS_REG                       0x0A
+#define REG_ALARM_MONTHS_REG                     0x0B
+#define REG_ALARM_YEARS_REG                      0x0C
+
+#define REG_RTC_CTRL_REG                         0x0D
+#define REG_RTC_STATUS_REG                       0x0E
+#define REG_RTC_INTERRUPTS_REG                   0x0F
+
+#define REG_RTC_COMP_LSB_REG                     0x10
+#define REG_RTC_COMP_MSB_REG                     0x11
+
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
+#define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
+#define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
+#define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
+#define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
+
+/* RTC_STATUS_REG bitfields */
+#define BIT_RTC_STATUS_REG_RUN_M                 0x02
+#define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
+#define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
+#define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
+#define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
+#define BIT_RTC_STATUS_REG_ALARM_M               0x40
+#define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
+
+/* RTC_INTERRUPTS_REG bitfields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
+
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+#define ALL_TIME_REGS          6
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Supports 1 byte read from TWL4030 RTC register.
+ */
+static int twl4030_rtc_read_u8(u8 *data, u8 reg)
+{
+       int ret;
+
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg);
+       if (ret < 0)
+               pr_err("twl4030_rtc: Could not read TWL4030"
+                      "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Supports 1 byte write to TWL4030 RTC registers.
+ */
+static int twl4030_rtc_write_u8(u8 data, u8 reg)
+{
+       int ret;
+
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg);
+       if (ret < 0)
+               pr_err("twl4030_rtc: Could not write TWL4030"
+                      "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+static unsigned char rtc_irq_bits;
+
+/*
+ * Enable timer and/or alarm interrupts.
+ */
+static int set_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits | bit;
+       ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+/*
+ * Disable timer and/or alarm interrupts.
+ */
+static int mask_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits & ~bit;
+       ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+       return ret;
+}
+
+static inline int twl4030_rtc_irq_set_state(int enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+       return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC time and date parameters.
+ *
+ * The RTC's time/alarm representation is not what gmtime(3) requires
+ * Linux to use:
+ *
+ *  - Months are 1..12 vs Linux 0-11
+ *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
+ */
+static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+       u8 save_control;
+
+       ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               return ret;
+
+       save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
+
+       ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               return ret;
+
+       ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+                              REG_SECONDS_REG, ALL_TIME_REGS);
+
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(rtc_data[0]);
+       tm->tm_min = bcd2bin(rtc_data[1]);
+       tm->tm_hour = bcd2bin(rtc_data[2]);
+       tm->tm_mday = bcd2bin(rtc_data[3]);
+       tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+       tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       return ret;
+}
+
+static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char save_control;
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       rtc_data[1] = bin2bcd(tm->tm_sec);
+       rtc_data[2] = bin2bcd(tm->tm_min);
+       rtc_data[3] = bin2bcd(tm->tm_hour);
+       rtc_data[4] = bin2bcd(tm->tm_mday);
+       rtc_data[5] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[6] = bin2bcd(tm->tm_year - 100);
+
+       /* Stop RTC while updating the TC registers */
+       ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out;
+
+       save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
+       twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out;
+
+       /* update all the time registers in one shot */
+       ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data,
+                       REG_SECONDS_REG, ALL_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_set_time error %d\n", ret);
+               goto out;
+       }
+
+       /* Start back RTC */
+       save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+       ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
+
+out:
+       return ret;
+}
+
+/*
+ * Gets current TWL4030 RTC alarm time.
+ */
+static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data,
+                              REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_alarm error %d\n", ret);
+               return ret;
+       }
+
+       /* some of these fields may be wildcard/"match all" */
+       alm->time.tm_sec = bcd2bin(rtc_data[0]);
+       alm->time.tm_min = bcd2bin(rtc_data[1]);
+       alm->time.tm_hour = bcd2bin(rtc_data[2]);
+       alm->time.tm_mday = bcd2bin(rtc_data[3]);
+       alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
+       alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       /* report cached alarm enable state */
+       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+               alm->enabled = 1;
+
+       return ret;
+}
+
+static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char alarm_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = twl4030_rtc_alarm_irq_set_state(0);
+       if (ret)
+               goto out;
+
+       alarm_data[1] = bin2bcd(alm->time.tm_sec);
+       alarm_data[2] = bin2bcd(alm->time.tm_min);
+       alarm_data[3] = bin2bcd(alm->time.tm_hour);
+       alarm_data[4] = bin2bcd(alm->time.tm_mday);
+       alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
+       alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
+
+       /* update all the alarm registers in one shot */
+       ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data,
+                       REG_ALARM_SECONDS_REG, ALL_TIME_REGS);
+       if (ret) {
+               dev_err(dev, "rtc_set_alarm error %d\n", ret);
+               goto out;
+       }
+
+       if (alm->enabled)
+               ret = twl4030_rtc_alarm_irq_set_state(1);
+out:
+       return ret;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd,
+                            unsigned long arg)
+{
+       switch (cmd) {
+       case RTC_AIE_OFF:
+               return twl4030_rtc_alarm_irq_set_state(0);
+       case RTC_AIE_ON:
+               return twl4030_rtc_alarm_irq_set_state(1);
+       case RTC_UIE_OFF:
+               return twl4030_rtc_irq_set_state(0);
+       case RTC_UIE_ON:
+               return twl4030_rtc_irq_set_state(1);
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+#else
+#define        omap_rtc_ioctl  NULL
+#endif
+
+static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)
+{
+       unsigned long events = 0;
+       int ret = IRQ_NONE;
+       int res;
+       u8 rd_reg;
+
+       res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+       if (res)
+               goto out;
+       /*
+        * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
+        * only one (ALARM or RTC) interrupt source may be enabled
+        * at time, we also could check our results
+        * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
+        */
+       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+               events |= RTC_IRQF | RTC_AF;
+       else
+               events |= RTC_IRQF | RTC_UF;
+
+       res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
+                                  REG_RTC_STATUS_REG);
+       if (res)
+               goto out;
+
+       /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
+        * needs 2 reads to clear the interrupt. One read is done in
+        * do_twl4030_pwrirq(). Doing the second read, to clear
+        * the bit.
+        *
+        * FIXME the reason PWR_ISR1 needs an extra read is that
+        * RTC_IF retriggered until we cleared REG_ALARM_M above.
+        * But re-reading like this is a bad hack; by doing so we
+        * risk wrongly clearing status for some other IRQ (losing
+        * the interrupt).  Be smarter about handling RTC_UF ...
+        */
+       res = twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                       &rd_reg, TWL4030_INT_PWR_ISR1);
+       if (res)
+               goto out;
+
+       /* Notify RTC core on event */
+       rtc_update_irq(rtc, 1, events);
+
+       ret = IRQ_HANDLED;
+out:
+       return ret;
+}
+
+static struct rtc_class_ops twl4030_rtc_ops = {
+       .ioctl          = twl4030_rtc_ioctl,
+       .read_time      = twl4030_rtc_read_time,
+       .set_time       = twl4030_rtc_set_time,
+       .read_alarm     = twl4030_rtc_read_alarm,
+       .set_alarm      = twl4030_rtc_set_alarm,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       int ret = 0;
+       int irq = platform_get_irq(pdev, 0);
+       u8 rd_reg;
+
+       if (irq < 0)
+               return irq;
+
+       rtc = rtc_device_register(pdev->name,
+                                 &pdev->dev, &twl4030_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+                       PTR_ERR(rtc));
+               goto out0;
+
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
+
+       if (ret < 0)
+               goto out1;
+
+       if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
+               dev_warn(&pdev->dev, "Power up reset detected.\n");
+
+       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+               dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
+
+       /* Clear RTC Power up reset and pending alarm interrupts */
+       ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
+       if (ret < 0)
+               goto out1;
+
+       ret = request_irq(irq, twl4030_rtc_interrupt,
+                               0, rtc->dev.bus_id, rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "IRQ is not free.\n");
+               goto out1;
+       }
+
+       /* Check RTC module status, Enable if it is off */
+       ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
+       if (ret < 0)
+               goto out2;
+
+       if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
+               dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n");
+               rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
+               ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
+               if (ret < 0)
+                       goto out2;
+       }
+
+       /* FIXME stop touching MODULE_INT registers; there's already
+        * driver code responsible for them.
+        */
+
+       /* use rising edge detection for RTC alarm */
+       ret = twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+                       &rd_reg, TWL4030_INT_PWR_EDR1);
+       if (ret < 0)
+               goto out2;
+
+       rd_reg |= BIT(3);
+       ret = twl4030_i2c_write_u8(TWL4030_MODULE_INT,
+                       rd_reg, TWL4030_INT_PWR_EDR1);
+       if (ret < 0)
+               goto out2;
+
+       /* init cached IRQ enable bits */
+       ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
+       if (ret < 0)
+               goto out2;
+
+       return ret;
+
+
+out2:
+       free_irq(irq, rtc);
+out1:
+       rtc_device_unregister(rtc);
+out0:
+       return ret;
+}
+
+/*
+ * Disable all TWL4030 RTC module interrupts.
+ * Sets status flag to free.
+ */
+static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
+{
+       /* leave rtc running, but disable irqs */
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+       free_irq(irq, rtc);
+
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static void twl4030_rtc_shutdown(struct platform_device *pdev)
+{
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
+                        BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+}
+
+#ifdef CONFIG_PM
+
+static unsigned char irqstat;
+
+static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       irqstat = rtc_irq_bits;
+
+       /* REVISIT alarm may need to wake us from sleep */
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
+                        BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       return 0;
+}
+
+static int twl4030_rtc_resume(struct platform_device *pdev)
+{
+       set_rtc_irq_bit(irqstat);
+       return 0;
+}
+
+#else
+#define twl4030_rtc_suspend NULL
+#define twl4030_rtc_resume  NULL
+#endif
+
+MODULE_ALIAS("platform:twl4030_rtc");
+
+static struct platform_driver twl4030rtc_driver = {
+       .probe          = twl4030_rtc_probe,
+       .remove         = __devexit_p(twl4030_rtc_remove),
+       .shutdown       = twl4030_rtc_shutdown,
+       .suspend        = twl4030_rtc_suspend,
+       .resume         = twl4030_rtc_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "twl4030_rtc",
+       },
+};
+
+static int __init twl4030_rtc_init(void)
+{
+       return platform_driver_register(&twl4030rtc_driver);
+}
+module_init(twl4030_rtc_init);
+
+static void __exit twl4030_rtc_exit(void)
+{
+       platform_driver_unregister(&twl4030rtc_driver);
+}
+module_exit(twl4030_rtc_exit);
+
+MODULE_AUTHOR("Texas Instruments, MontaVista Software");
+MODULE_LICENSE("GPL");
index 9ccc563d87303604c8cd63f355040177c30faf81..39aca22e57a843e821e777fb1d1edf394f1840c8 100644 (file)
@@ -1513,7 +1513,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
 }
 
 /*
@@ -2211,9 +2215,9 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
                serial_outp(up, UART_EFR, efr);
        }
 
-#ifdef CONFIG_ARCH_OMAP15XX
+#ifdef CONFIG_ARCH_OMAP
        /* Workaround to enable 115200 baud on OMAP1510 internal ports */
-       if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+       if (cpu_is_omap1510() && is_omap_port(up)) {
                if (baud == 115200) {
                        quot = 1;
                        serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
@@ -2245,6 +2249,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);
@@ -2266,18 +2283,27 @@ serial8250_pm(struct uart_port *port, unsigned int state,
                p->pm(port, state, oldstate);
 }
 
+static unsigned int serial8250_port_size(struct uart_8250_port *pt)
+{
+       if (pt->port.iotype == UPIO_AU)
+               return 0x100000;
+#ifdef CONFIG_ARCH_OMAP
+       if (is_omap_port(pt))
+               return 0x16 << pt->port.regshift;
+#endif
+       return 8 << pt->port.regshift;
+}
+
 /*
  * Resource handling.
  */
 static int serial8250_request_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
        int ret = 0;
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
@@ -2311,12 +2337,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
 
 static void serial8250_release_std_resource(struct uart_8250_port *up)
 {
-       unsigned int size = 8 << up->port.regshift;
+       unsigned int size = serial8250_port_size(up);
 
        switch (up->port.iotype) {
        case UPIO_AU:
-               size = 0x100000;
-               /* fall thru */
        case UPIO_TSI:
        case UPIO_MEM32:
        case UPIO_MEM:
index b9d0efb6803f2919695c21ed6ba186303c51353c..c04029a859837ecb87336c8f23bf65e03584351b 100644 (file)
@@ -225,6 +225,62 @@ config SPI_AT25
          This driver can also be built as a module.  If so, the module
          will be called at25.
 
+config SPI_TSC2101
+       depends on SPI_MASTER
+       tristate "TSC2101 chip support"
+       ---help---
+         Say Y here if you want support for the TSC2101 chip.
+        At the moment it provides basic register read / write interface
+        as well as a way to enable the MCLK clock.
+        
+config SPI_TSC2102
+       depends on SPI_MASTER
+       tristate "TSC2102 codec support"
+       ---help---
+         Say Y here if you want support for the TSC2102 chip.  It
+        will be needed for the touchscreen driver on some boards.
+
+config SPI_TSC210X
+       depends on SPI_MASTER && EXPERIMENTAL
+       tristate "TI TSC210x (TSC2101/TSC2102) support"
+       help
+         Say Y here if you want support for the TSC210x chips.  Some
+         boards use these for touchscreen and audio support.
+
+         These are members of a family of highly integrated PDA analog
+         interface circuit.  They include a 12-bit ADC used for battery,
+         temperature, touchscreen, and other sensors.  They also have
+         an audio DAC and amplifier, and in some models an audio ADC.
+         The audio support is highly chip-specific, but most of the
+         sensor support works the same.
+
+         Note that the device has to be present in the board's SPI
+         devices table for this driver to load.  This driver doesn't
+         automatically enable touchscreen, sensors or audio
+         functionality - enable these in their respective menus.
+
+config SPI_TSC2301
+       tristate "TSC2301 driver"
+       depends on SPI_MASTER
+       help
+         Say Y here if you have a TSC2301 chip connected to an SPI
+         bus on your board.
+
+         The TSC2301 is a highly integrated PDA analog interface circuit.
+         It contains a complete 12-bit A/D resistive touch screen
+         converter (ADC) including drivers, touch pressure measurement
+         capability, keypad controller, and 8-bit D/A converter (DAC) output
+         for LCD contrast control.
+
+         To compile this driver as a module, choose M here: the
+         module will be called tsc2301.
+
+config SPI_TSC2301_AUDIO
+       boolean "TSC2301 audio support"
+       depends on SPI_TSC2301 && SND
+       help
+         Say Y here for if you are using the audio features of TSC2301.
+
 config SPI_SPIDEV
        tristate "User mode SPI device driver support"
        depends on EXPERIMENTAL
index ccf18de34e1e0df26a697b2939d58c7e62cf231d..1c2e7fc928e38f8217b9432aa7074909f77ca98a 100644 (file)
@@ -35,6 +35,12 @@ obj-$(CONFIG_SPI_SH_SCI)             += spi_sh_sci.o
 obj-$(CONFIG_SPI_AT25)         += at25.o
 obj-$(CONFIG_SPI_SPIDEV)       += spidev.o
 obj-$(CONFIG_SPI_TLE62X0)      += tle62x0.o
+obj-$(CONFIG_SPI_TSC2101)      += tsc2101.o
+obj-$(CONFIG_SPI_TSC2102)      += tsc2102.o
+obj-$(CONFIG_SPI_TSC210X)      += tsc210x.o
+obj-$(CONFIG_SPI_TSC2301)      += tsc2301.o
+tsc2301-objs                   := tsc2301-core.o
+tsc2301-$(CONFIG_SPI_TSC2301_AUDIO)    += tsc2301-mixer.o
 #      ... add above this line ...
 
 # SPI slave controller drivers (upstream link)
index 9d2186fd74aaf7eaca9f9954dde88d1dc11e7c36..454a2712e6290ee0f0f085667a0baec9ec6bb027 100644 (file)
@@ -119,12 +119,14 @@ struct omap2_mcspi {
        struct clk              *fck;
        /* Virtual base address of the controller */
        void __iomem            *base;
+       unsigned long           phys;
        /* SPI1 has 4 channels, while SPI2 has 2 */
        struct omap2_mcspi_dma  *dma_channels;
 };
 
 struct omap2_mcspi_cs {
        void __iomem            *base;
+       unsigned long           phys;
        int                     word_len;
 };
 
@@ -233,7 +235,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        c = count;
        word_len = cs->word_len;
 
-       base = (unsigned long) io_v2p(cs->base);
+       base = cs->phys;
        tx_reg = base + OMAP2_MCSPI_TX0;
        rx_reg = base + OMAP2_MCSPI_RX0;
        rx = xfer->rx_buf;
@@ -633,6 +635,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                if (!cs)
                        return -ENOMEM;
                cs->base = mcspi->base + spi->chip_select * 0x14;
+               cs->phys = mcspi->phys + spi->chip_select * 0x14;
                spi->controller_state = cs;
        }
 
@@ -1005,7 +1008,13 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       mcspi->base = (void __iomem *) io_p2v(r->start);
+       mcspi->phys = r->start;
+       mcspi->base = ioremap(r->start, r->end - r->start + 1);
+       if (!mcspi->base) {
+               dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
+               status = -ENOMEM;
+               goto err1aa;
+       }
 
        INIT_WORK(&mcspi->work, omap2_mcspi_work);
 
@@ -1055,6 +1064,8 @@ err3:
 err2:
        clk_put(mcspi->ick);
 err1a:
+       iounmap(mcspi->base);
+err1aa:
        release_mem_region(r->start, (r->end - r->start) + 1);
 err1:
        spi_master_put(master);
@@ -1067,6 +1078,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *dma_channels;
        struct resource         *r;
+       void __iomem *base;
 
        master = dev_get_drvdata(&pdev->dev);
        mcspi = spi_master_get_devdata(master);
@@ -1078,7 +1090,9 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        release_mem_region(r->start, (r->end - r->start) + 1);
 
+       base = mcspi->base;
        spi_unregister_master(master);
+       iounmap(base);
        kfree(dma_channels);
 
        return 0;
index 5515eb97d7c57ebacdcc7c4379822af0dd5bb751..bab6ff061e9145a95dad6756d6cbc4b25e69e671 100644 (file)
@@ -59,7 +59,6 @@
  * 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
@@ -103,16 +102,21 @@ struct uwire_state {
 };
 
 /* REVISIT compile time constant for idx_shift? */
+/*
+ * Or, put it in a structure which is used throughout the driver;
+ * that avoids having to issue two loads for each bit of static data.
+ */
 static unsigned int uwire_idx_shift;
+static void __iomem *uwire_base;
 
 static inline void uwire_write_reg(int idx, u16 val)
 {
-       __raw_writew(val, UWIRE_BASE + (idx << uwire_idx_shift));
+       __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));
+       return __raw_readw(uwire_base + (idx << uwire_idx_shift));
 }
 
 static inline void omap_uwire_configure_mode(u8 cs, unsigned long flags)
@@ -492,6 +496,14 @@ static int __init uwire_probe(struct platform_device *pdev)
                return -ENODEV;
 
        uwire = spi_master_get_devdata(master);
+
+       uwire_base = ioremap(UWIRE_BASE_PHYS, UWIRE_IO_SIZE);
+       if (!uwire_base) {
+               dev_dbg(&pdev->dev, "can't ioremap UWIRE\n");
+               spi_master_put(master);
+               return -ENOMEM;
+       }
+
        dev_set_drvdata(&pdev->dev, uwire);
 
        uwire->ck = clk_get(&pdev->dev, "armxor_ck");
@@ -520,8 +532,10 @@ static int __init uwire_probe(struct platform_device *pdev)
        uwire->bitbang.txrx_bufs = uwire_txrx;
 
        status = spi_bitbang_start(&uwire->bitbang);
-       if (status < 0)
+       if (status < 0) {
                uwire_off(uwire);
+               iounmap(uwire_base);
+       }
        return status;
 }
 
@@ -534,6 +548,7 @@ static int __exit uwire_remove(struct platform_device *pdev)
 
        status = spi_bitbang_stop(&uwire->bitbang);
        uwire_off(uwire);
+       iounmap(uwire_base);
        return status;
 }
 
diff --git a/drivers/spi/tsc2101.c b/drivers/spi/tsc2101.c
new file mode 100644 (file)
index 0000000..71702e2
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * linux/drivers/spi/tsc2101.c
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Modified for common hooks for Audio and Touchscreen
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2101.h>
+
+struct tsc2101_device {
+       struct mutex            mutex;
+       int                     mclk_enabled;
+       struct clock            *mclk_ck;
+       struct spi_message      message;
+       struct spi_transfer     transfer[2];
+       u16                     command;
+       void                    (*enable_mclk)(struct spi_device *spi);
+       void                    (*disable_mclk)(struct spi_device *spi);
+};
+
+int tsc2101_enable_mclk(struct spi_device *spi)
+{
+       struct tsc2101_device *tsc2101;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       mutex_lock(&tsc2101->mutex);
+
+       if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+               mutex_unlock(&tsc2101->mutex);
+               return -ENODEV;
+       }
+
+       if (tsc2101->mclk_enabled++ == 0) {
+               if (tsc2101->enable_mclk != NULL)
+                       tsc2101->enable_mclk(spi);
+       }
+
+       mutex_unlock(&tsc2101->mutex);
+       return 0;
+}
+EXPORT_SYMBOL(tsc2101_enable_mclk);
+
+void tsc2101_disable_mclk(struct spi_device *spi)
+{
+       struct tsc2101_device *tsc2101;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       mutex_lock(&tsc2101->mutex);
+
+       if (--tsc2101->mclk_enabled == 0) {
+               if (tsc2101->disable_mclk != NULL &&
+                   spi->dev.power.power_state.event == PM_EVENT_ON)
+                       tsc2101->disable_mclk(spi);
+       }
+
+       mutex_lock(&tsc2101->mutex);
+}
+EXPORT_SYMBOL(tsc2101_disable_mclk);
+
+int tsc2101_write_sync(struct spi_device *spi, int page, u8 address, u16 data)
+{
+       struct tsc2101_device *tsc2101;
+       struct spi_message *m;
+       struct spi_transfer *t;
+       int ret;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       mutex_lock(&tsc2101->mutex);
+       if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+               mutex_unlock(&tsc2101->mutex);
+               return -ENODEV;
+       }
+
+       m = &tsc2101->message;
+       spi_message_init(m);
+       t = &tsc2101->transfer[0];
+       memset(t, 0, sizeof(tsc2101->transfer));
+
+       /* Address */
+       tsc2101->command = (page << 11) | (address << 5);
+       t->tx_buf = &tsc2101->command;
+       t->len = 2;
+       spi_message_add_tail(t, m);
+
+       /* Data */
+       t++;
+       t->tx_buf = &data;
+       t->len = 2;
+       spi_message_add_tail(t, m);
+
+       ret = spi_sync(spi, m);
+       if (!ret)
+               ret = tsc2101->message.status;
+       mutex_unlock(&tsc2101->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(tsc2101_write_sync);
+
+int tsc2101_reads_sync(struct spi_device *spi,
+                      int page, u8 startaddress, u16 *data, int numregs)
+{
+       struct tsc2101_device *tsc2101;
+       struct spi_message *m;
+       struct spi_transfer *t;
+       int ret;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       mutex_lock(&tsc2101->mutex);
+       if (spi->dev.power.power_state.event != PM_EVENT_ON) {
+               mutex_unlock(&tsc2101->mutex);
+               return -ENODEV;
+       }
+
+       m = &tsc2101->message;
+       spi_message_init(m);
+       t = &tsc2101->transfer[0];
+       memset(t, 0, sizeof(tsc2101->transfer));
+
+       /* Address */
+       tsc2101->command = 0x8000 | (page << 11) | (startaddress << 5);
+       t->tx_buf = &tsc2101->command;
+       t->len = 2;
+       spi_message_add_tail(t, m);
+
+       /* Data */
+       t++;
+       t->rx_buf = data;
+       t->len = numregs << 1;
+       spi_message_add_tail(t, m);
+
+       ret = spi_sync(spi, m);
+       if (!ret)
+               ret = tsc2101->message.status;
+
+       mutex_unlock(&tsc2101->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(tsc2101_reads_sync);
+
+int tsc2101_read_sync(struct spi_device *spi, int page, u8 address)
+{
+       int err;
+       u16 val;
+
+       err = tsc2101_reads_sync(spi, page, address, &val, 1);
+       if (err)
+               return err;
+       return val;
+}
+EXPORT_SYMBOL(tsc2101_read_sync);
+
+static int tsc2101_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct tsc2101_device *tsc2101;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       if (tsc2101 == NULL)
+               return 0;
+
+       mutex_lock(&tsc2101->mutex);
+
+       spi->dev.power.power_state = state;
+       if (tsc2101->mclk_enabled && tsc2101->disable_mclk != NULL)
+               tsc2101->disable_mclk(spi);
+
+       mutex_unlock(&tsc2101->mutex);
+
+       return 0;
+}
+
+static int tsc2101_resume(struct spi_device *spi)
+{
+       struct tsc2101_device *tsc2101;
+
+       tsc2101 = spi_get_drvdata(spi);
+
+       if (tsc2101 == NULL)
+               return 0;
+
+       mutex_lock(&tsc2101->mutex);
+
+       spi->dev.power.power_state = PMSG_ON;
+       if (tsc2101->mclk_enabled && tsc2101->enable_mclk != NULL)
+               tsc2101->enable_mclk(spi);
+
+       mutex_unlock(&tsc2101->mutex);
+
+       return 0;
+}
+
+static int tsc2101_probe(struct spi_device *spi)
+{
+       struct tsc2101_platform_data *pdata;
+       struct tsc2101_device *tsc2101;
+       u16 w;
+       int r;
+
+       pdata = spi->dev.platform_data;
+       if (pdata == NULL) {
+               dev_err(&spi->dev, "no platform data\n");
+               return -ENODEV;
+       }
+
+       tsc2101 = kzalloc(sizeof(*tsc2101), GFP_KERNEL);
+       if (tsc2101 == NULL) {
+               dev_err(&spi->dev, "out of mem\n");
+               return -ENOMEM;
+       }
+
+       spi_set_drvdata(spi, tsc2101);
+       tsc2101->enable_mclk = pdata->enable_mclk;
+       tsc2101->disable_mclk = pdata->disable_mclk;
+
+       mutex_init(&tsc2101->mutex);
+
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       if ((r = spi_setup(spi)) < 0) {
+               dev_err(&spi->dev, "SPI setup failed\n");
+               goto err;
+       }
+
+       w = tsc2101_read_sync(spi, 1, 0);
+       if (!(w & (1 << 14))) {
+               dev_err(&spi->dev, "invalid ADC register value %04x\n", w);
+               goto err;
+       }
+
+       if (pdata->init != NULL) {
+               if ((r = pdata->init(spi)) < 0) {
+                       dev_err(&spi->dev, "platform init failed\n");
+                       goto err;
+               }
+       }
+
+       dev_info(&spi->dev, "initialized\n");
+
+       return 0;
+err:
+       kfree(tsc2101);
+       return r;
+}
+
+static int tsc2101_remove(struct spi_device *spi)
+{
+       struct tsc2101_platform_data *pdata;
+       struct tsc2101_device *tsc2101;
+
+       pdata = spi->dev.platform_data;
+       tsc2101 = spi_get_drvdata(spi);
+
+       /* We assume that this can't race with the rest of the driver. */
+       if (tsc2101->mclk_enabled && tsc2101->disable_mclk != NULL)
+               tsc2101->disable_mclk(spi);
+
+       if (pdata->cleanup != NULL)
+               pdata->cleanup(spi);
+
+       spi_set_drvdata(spi, NULL);
+       kfree(tsc2101);
+
+       return 0;
+}
+
+static struct spi_driver tsc2101_driver = {
+       .probe          = tsc2101_probe,
+       .remove         = tsc2101_remove,
+       .suspend        = tsc2101_suspend,
+       .resume         = tsc2101_resume,
+       .driver         = {
+               .name   = "tsc2101",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int tsc2101_init(void)
+{
+       return spi_register_driver(&tsc2101_driver);
+}
+
+static void tsc2101_exit(void)
+{
+       spi_unregister_driver(&tsc2101_driver);
+}
+
+module_init(tsc2101_init);
+module_exit(tsc2101_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION
+    ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc2102.c b/drivers/spi/tsc2102.c
new file mode 100644 (file)
index 0000000..59171ca
--- /dev/null
@@ -0,0 +1,1207 @@
+/*
+ * drivers/spi/tsc2102.c
+ *
+ * TSC2102 interface driver.
+ *
+ * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2102.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#ifdef CONFIG_APM
+#include <asm/apm.h>
+#endif
+
+/* Bit field definitions for chip registers */
+#define TSC2102_ADC_TS_CONTROL         0x8bf4
+#define TSC2102_ADC_SCAN_CONTROL       0x2ff4
+#define TSC2102_ADC_T1_CONTROL         0x2bf4
+#define TSC2102_ADC_T2_CONTROL         0x33f4
+#define TSC2102_ADC_DAV                        0x4000
+#define TSC2102_ADC_INT_REF            0x0016
+#define TSC2102_ADC_EXT_REF            0x0002
+#define TSC2102_CONFIG_TIMES           0x0008
+#define TSC2102_RESET                  0xbb00
+#define TSC2102_ADC_PSTCM              (1 << 15)
+#define TSC2102_ADC_ADST               (1 << 14)
+#define TSC2102_TS_DAV                 0x0780
+#define TSC2102_PS_DAV                 0x0078
+#define TSC2102_T1_DAV                 0x0004
+#define TSC2102_T2_DAV                 0x0002
+#define TSC2102_DAC_ON                 0x3ba0
+#define TSC2102_DAC_OFF                        0xafa0
+#define TSC2102_FS44K                  (1 << 13)
+#define TSC2102_PLL1_OFF               0x0000
+#define TSC2102_PLL1_44K               0x811c
+#define TSC2102_PLL1_48K               0x8120
+#define TSC2102_PLL2_44K               (5462 << 2)
+#define TSC2102_PLL2_48K               (1920 << 2)
+#define TSC2102_SLVMS                  (1 << 11)
+#define TSC2102_DEEMPF                 (1 << 0)
+#define TSC2102_BASSBC                 (1 << 1)
+#define TSC2102_KEYCLICK_OFF           0x0000
+
+#define CS_CHANGE(val)                 0
+
+struct tsc2102_spi_req {
+       struct spi_device *dev;
+       uint16_t command;
+       uint16_t data;
+       struct spi_transfer *transfer;
+       struct spi_message message;
+};
+
+struct tsc2102_dev {
+       struct tsc2102_config *pdata;
+       spinlock_t lock, lock_sync;
+       struct clk *bclk_ck;
+
+       int state;                      /* 0: TS, 1: Portscan, 2-3: Temps */
+       struct timer_list ts_timer;     /* Busy-wait for PEN UP */
+       struct timer_list mode_timer;   /* Change .state every some time */
+       int pendown;
+       int data_pending;
+       uint16_t status, adc_status, adc_data[4];
+       tsc2102_touch_t touch_cb;
+       tsc2102_coords_t coords_cb;
+       tsc2102_ports_t ports_cb;
+       tsc2102_temp_t temp1_cb;
+       tsc2102_temp_t temp2_cb;
+       unsigned int ts_msecs;          /* Interval for .ts_timer */
+       unsigned int mode_msecs;        /* Interval for .mode_timer */
+
+       struct spi_device *spi;
+       struct spi_transfer *transfers;
+       struct tsc2102_spi_req req_adc;
+       struct tsc2102_spi_req req_status;
+       struct tsc2102_spi_req req_pressure;
+       struct tsc2102_spi_req req_stopadc;
+       struct tsc2102_spi_req req_mode;
+
+       int bat[2], aux[1], temp[2];
+       struct class_device *hwmondev;
+};
+
+static struct tsc2102_dev tsc;
+
+module_param_named(touch_check_msecs, tsc.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, tsc.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+void tsc2102_write_sync(int page, u8 address, u16 data)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[2];
+       int ret;
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+
+       /* Address */
+       req.command = (page << 11) | (address << 5);
+       req.transfer[0].tx_buf = &req.command;
+       req.transfer[0].rx_buf = 0;
+       req.transfer[0].len = 2;
+       spi_message_add_tail(&req.transfer[0], &req.message);
+
+       /* Data */
+       req.transfer[1].tx_buf = &data;
+       req.transfer[1].rx_buf = 0;
+       req.transfer[1].len = 2;
+       req.transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&req.transfer[1], &req.message);
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+void tsc2102_reads_sync(int page, u8 startaddress, u16 *data, int numregs)
+{
+       static struct tsc2102_spi_req req;
+       static struct spi_transfer transfer[6];
+       int ret, i, j;
+
+       BUG_ON(numregs + 1 > ARRAY_SIZE(transfer));
+
+       spi_message_init(&req.message);
+       req.transfer = transfer;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       req.command = 0x8000 | (page << 11) | (startaddress << 5);
+       req.transfer[i].tx_buf = &req.command;
+       req.transfer[i].rx_buf = 0;
+       req.transfer[i].len = 2;
+       spi_message_add_tail(&req.transfer[i ++], &req.message);
+
+       /* Data */
+       while (j < numregs) {
+               req.transfer[i].tx_buf = 0;
+               req.transfer[i].rx_buf = &data[j ++];
+               req.transfer[i].len = 2;
+               req.transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&req.transfer[i ++], &req.message);
+       }
+
+       ret = spi_sync(tsc.spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+u16 tsc2102_read_sync(int page, u8 address)
+{
+       u16 ret;
+       tsc2102_reads_sync(page, address, &ret, 1);
+       return ret;
+}
+
+static void tsc2102_write_async(
+               struct tsc2102_spi_req *spi, int page, u8 address, u16 data,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+
+       /* Address */
+       spi->command = (page << 11) | (address << 5);
+       spi->transfer[0].tx_buf = &spi->command;
+       spi->transfer[0].rx_buf = 0;
+       spi->transfer[0].len = 2;
+       spi_message_add_tail(&spi->transfer[0], &spi->message);
+
+       /* Data */
+       spi->data = data;
+       spi->transfer[1].tx_buf = &spi->data;
+       spi->transfer[1].rx_buf = 0;
+       spi->transfer[1].len = 2;
+       spi->transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&spi->transfer[1], &spi->message);
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_reads_async(struct tsc2102_spi_req *spi,
+               int page, u8 startaddress, u16 *data, int numregs,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       int ret, i, j;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = &tsc;
+       i = 0;
+       j = 0;
+
+       /* Address */
+       spi->command = 0x8000 | (page << 11) | (startaddress << 5);
+       spi->transfer[i].tx_buf = &spi->command;
+       spi->transfer[i].rx_buf = 0;
+       spi->transfer[i].len = 2;
+       spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+
+       /* Data */
+       while (j < numregs) {
+               spi->transfer[i].tx_buf = 0;
+               spi->transfer[i].rx_buf = &data[j ++];
+               spi->transfer[i].len = 2;
+               spi->transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&spi->transfer[i ++], &spi->message);
+       }
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               printk(KERN_ERR "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc2102_read_async(struct tsc2102_spi_req *spi,
+               int page, u8 address, u16 *ret,
+               void (*complete)(struct tsc2102_dev *context))
+{
+       tsc2102_reads_async(spi, page, address, ret, 1, complete);
+}
+
+static void tsc2102_request_alloc(struct tsc2102_dev *dev,
+               struct tsc2102_spi_req *spi, int direction, int numregs,
+               struct spi_transfer **buffer)
+{
+       spi->dev = dev->spi;
+
+       if (direction == 1)     /* Write */
+               numregs = 2;
+       else                    /* Read */
+               numregs += 1;
+
+       spi->transfer = *buffer;
+       *buffer += numregs;
+}
+
+#define tsc2102_cb_register_func(cb, cb_t)     \
+int tsc2102_ ## cb(cb_t handler)       \
+{      \
+       spin_lock(&tsc.lock);   \
+       \
+       /* Lock the module */   \
+       if (handler && !tsc.cb) \
+               if (!try_module_get(THIS_MODULE)) {     \
+                       printk(KERN_INFO "Failed to get TSC module\n"); \
+               }       \
+       if (!handler && tsc.cb) \
+               module_put(THIS_MODULE);        \
+       \
+       tsc.cb = handler;       \
+       \
+       spin_unlock(&tsc.lock); \
+       return 0;       \
+}
+
+tsc2102_cb_register_func(touch_cb, tsc2102_touch_t)
+tsc2102_cb_register_func(coords_cb, tsc2102_coords_t)
+tsc2102_cb_register_func(ports_cb, tsc2102_ports_t)
+tsc2102_cb_register_func(temp1_cb, tsc2102_temp_t)
+tsc2102_cb_register_func(temp2_cb, tsc2102_temp_t)
+
+#ifdef DEBUG
+static void tsc2102_print_dav(void)
+{
+       u16 status = tsc2102_read_sync(TSC2102_TS_STATUS_CTRL);
+       if (status & 0x0fff)
+               printk("TSC2102: data in");
+       if (status & 0x0400)
+               printk(" X");
+       if (status & 0x0200)
+               printk(" Y");
+       if (status & 0x0100)
+               printk(" Z1");
+       if (status & 0x0080)
+               printk(" Z2");
+       if (status & 0x0040)
+               printk(" BAT1");
+       if (status & 0x0020)
+               printk(" BAT2");
+       if (status & 0x0010)
+               printk(" AUX1");
+       if (status & 0x0008)
+               printk(" AUX2");
+       if (status & 0x0004)
+               printk(" TEMP1");
+       if (status & 0x0002)
+               printk(" TEMP2");
+       if (status & 0x0001)
+               printk(" KP");
+       if (status & 0x0fff)
+               printk(".\n");
+}
+#endif
+
+static void tsc2102_complete_dummy(struct tsc2102_dev *dev)
+{
+}
+
+static inline void tsc2102_touchscreen_mode(struct tsc2102_dev *dev)
+{
+       /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_TS_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_portscan_mode(struct tsc2102_dev *dev)
+{
+       /* Scan BAT1, BAT2, AUX, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_SCAN_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp1_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T1_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static inline void tsc2102_temp2_mode(struct tsc2102_dev *dev)
+{
+       /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+       tsc2102_write_async(&dev->req_mode,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_T2_CONTROL,
+                       tsc2102_complete_dummy);
+}
+
+static void tsc2102_mode(struct tsc2102_dev *dev)
+{
+       switch (dev->state) {
+       case 0:
+               tsc2102_touchscreen_mode(dev);
+               break;
+       case 1:
+               tsc2102_portscan_mode(dev);
+               break;
+       case 2:
+               tsc2102_temp1_mode(dev);
+               break;
+       case 3:
+               tsc2102_temp2_mode(dev);
+               break;
+       default:
+               dev->state = 0;
+               tsc2102_touchscreen_mode(dev);
+               break;
+       }
+}
+
+/* Lock is held when this is called.  */
+static void tsc2102_new_mode(struct tsc2102_dev *dev)
+{
+       /* Abort current conversion if any */
+       tsc2102_write_async(&dev->req_stopadc,
+                       TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST,
+                       tsc2102_complete_dummy);
+
+       dev->state ++;
+       tsc2102_mode(dev);
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev);
+
+/* TSC has new data for us availiable.  */
+static irqreturn_t tsc2102_handler(int irq, void *dev_id)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) dev_id;
+       spin_lock_irq(&dev->lock);
+
+       if (!dev->data_pending)
+               tsc2102_check_status(dev);
+
+       dev->data_pending ++;
+
+       spin_unlock_irq(&dev->lock);
+       return IRQ_HANDLED;
+}
+
+static void tsc2102_data_report(struct tsc2102_dev *dev)
+{
+       if (dev->status & TSC2102_TS_DAV) {
+               if (dev->coords_cb)
+                       dev->coords_cb(
+                                       dev->adc_data[0], dev->adc_data[1],
+                                       dev->adc_data[2], dev->adc_data[3]);
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               if (dev->ports_cb)
+                       dev->ports_cb(dev->adc_data[0],
+                                       dev->adc_data[1], dev->adc_data[2]);
+               dev->bat[0] = dev->adc_data[0];
+               dev->bat[1] = dev->adc_data[1];
+               dev->aux[0] = dev->adc_data[2];
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               if (dev->temp1_cb)
+                       dev->temp1_cb(*dev->adc_data);
+               dev->temp[0] = *dev->adc_data;
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               if (dev->temp2_cb)
+                       dev->temp2_cb(*dev->adc_data);
+               dev->temp[1] = *dev->adc_data;
+       }
+
+       spin_lock_irq(&dev->lock);
+
+       dev->data_pending --;
+
+       /*
+        * This may happen if the registers were successfully read and a
+        * new conversion was started and completed by the TSC before the
+        * completion for SPI read was called.
+        */
+       if (dev->data_pending)
+               tsc2102_check_status(dev);
+
+       if (dev->status & (TSC2102_PS_DAV | TSC2102_T1_DAV | TSC2102_T2_DAV))
+               tsc2102_new_mode(dev);
+
+       spin_unlock_irq(&dev->lock);
+}
+
+static void tsc2102_status_report(struct tsc2102_dev *dev)
+{
+       /*
+        * Read all converted data from corresponding registers
+        * so that the ADC can move on to a new conversion.
+        */
+       if (dev->status & TSC2102_TS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_X,
+                               dev->adc_data, 4, tsc2102_data_report);
+               if (!dev->pendown) {
+                       dev->pendown = 1;
+                       if (dev->touch_cb)
+                               dev->touch_cb(1);
+
+                       mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+               }
+       }
+
+       if (dev->status & TSC2102_PS_DAV) {
+               tsc2102_reads_async(&dev->req_adc, TSC2102_TS_BAT1,
+                               dev->adc_data, 3, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T1_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP1,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (dev->status & TSC2102_T2_DAV) {
+               tsc2102_read_async(&dev->req_adc, TSC2102_TS_TEMP2,
+                               dev->adc_data, tsc2102_data_report);
+       }
+
+       if (!(dev->status & (TSC2102_TS_DAV | TSC2102_PS_DAV |
+                                       TSC2102_T1_DAV | TSC2102_T2_DAV))) {
+               spin_lock_irq(&dev->lock);
+               dev->data_pending --;
+               spin_unlock_irq(&dev->lock);
+
+               WARN_ON(!dev->state);
+       }
+}
+
+static void tsc2102_check_status(struct tsc2102_dev *dev)
+{
+       tsc2102_read_async(&dev->req_status, TSC2102_TS_STATUS_CTRL,
+                       &dev->status, tsc2102_status_report);
+}
+
+static void tsc2102_mode_timer(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+       spin_lock_irq(&dev->lock);
+
+       BUG_ON(dev->state);
+
+       tsc2102_new_mode(dev);
+
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       spin_unlock_irq(&dev->lock);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ *     - the PINT/DAV pin state,
+ *     - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ *     - reading ADST bit in ADC Control register (D14, offset 0x00),
+ *             ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits.  So we will busy-wait
+ * for a moment when all three indicate a pen-up, using a timer, before
+ * we report a pen-up.
+ */
+static void tsc2102_pressure_report(struct tsc2102_dev *dev)
+{
+       if (!dev->pendown)
+               return;
+
+       if (dev->state ||
+                       (dev->adc_status & TSC2102_ADC_PSTCM) ||
+                       !(dev->adc_status & TSC2102_ADC_ADST)) {
+               mod_timer(&dev->ts_timer, jiffies +
+                               msecs_to_jiffies(dev->ts_msecs));
+       } else {
+               dev->pendown = 0;
+               if (dev->touch_cb)
+                       dev->touch_cb(0);
+       }
+}
+
+static void tsc2102_pressure(unsigned long data)
+{
+       struct tsc2102_dev *dev = (struct tsc2102_dev *) data;
+
+       BUG_ON(!dev->pendown);
+
+       tsc2102_read_async(&dev->req_pressure, TSC2102_TS_ADC_CTRL,
+                       &dev->adc_status, tsc2102_pressure_report);
+}
+
+#if defined(CONFIG_SND_OMAP_TSC2102) || defined(CONFIG_SND_OMAP_TSC2102_MODULE)
+
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch)
+{
+       u16 val;
+       if (left_ch == 0x00 || left_ch == 0x7f) /* All 0's or all 1's */
+               left_ch ^= 0x7f;
+       if (right_ch == 0x00 || right_ch == 0x7f)
+               right_ch ^= 0x7f;
+
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x8080;  /* Preserve mute-bits */
+       val |= (left_ch << 8) | right_ch;
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_volume);
+
+void tsc2102_set_mute(int left_ch, int right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       val &= 0x7f7f;  /* Preserve volume settings */
+       val |= (left_ch << 15) | (right_ch << 7);
+
+       tsc2102_write_sync(TSC2102_DAC_GAIN_CTRL, val);
+
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_mute);
+
+void tsc2102_get_mute(int *left_ch, int *right_ch)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL);
+
+       spin_unlock(&tsc.lock_sync);
+
+       *left_ch = !!(val & (1 << 15));
+       *right_ch = !!(val & (1 << 7));
+}
+
+void tsc2102_set_deemphasis(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_DEEMPF;
+       else
+               val |= TSC2102_DEEMPF;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_deemphasis);
+
+void tsc2102_set_bassboost(int enable)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_DAC_POWER_CTRL);
+
+       if (enable)
+               val &= ~TSC2102_BASSBC;
+       else
+               val |= TSC2102_BASSBC;
+
+       tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_bassboost);
+
+/*     {rate, dsor, fsref}     */
+static const struct tsc2102_rate_info_s tsc2102_rates[] = {
+       /* Fsref / 6.0 */
+       {7350,  63,     1},
+       {8000,  63,     0},
+       /* Fsref / 6.0 */
+       {7350,  54,     1},
+       {8000,  54,     0},
+       /* Fsref / 5.0 */
+       {8820,  45,     1},
+       {9600,  45,     0},
+       /* Fsref / 4.0 */
+       {11025, 36,     1},
+       {12000, 36,     0},
+       /* Fsref / 3.0 */
+       {14700, 27,     1},
+       {16000, 27,     0},
+       /* Fsref / 2.0 */
+       {22050, 18,     1},
+       {24000, 18,     0},
+       /* Fsref / 1.5 */
+       {29400, 9,      1},
+       {32000, 9,      0},
+       /* Fsref */
+       {44100, 0,      1},
+       {48000, 0,      0},
+
+       {0,     0,      0},
+};
+
+int tsc2102_set_rate(int rate)
+{
+       int i;
+       uint16_t val;
+
+       for (i = 0; tsc2102_rates[i].sample_rate; i ++)
+               if (tsc2102_rates[i].sample_rate == rate)
+                       break;
+       if (tsc2102_rates[i].sample_rate == 0) {
+               printk(KERN_ERR "Unknown sampling rate %i.0 Hz\n", rate);
+               return -EINVAL;
+       }
+
+       spin_lock(&tsc.lock_sync);
+
+       tsc2102_write_sync(TSC2102_AUDIO1_CTRL, tsc2102_rates[i].divisor);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (tsc2102_rates[i].fs_44k) {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+       } else {
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_48K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_48K);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+       return 0;
+}
+EXPORT_SYMBOL(tsc2102_set_rate);
+
+/*
+ * Perform basic set-up with default values and power the DAC on.
+ */
+void tsc2102_dac_power(int state)
+{
+       spin_lock(&tsc.lock_sync);
+
+       if (state) {
+               /* 16-bit words, DSP mode, sample at Fsref */
+               tsc2102_write_sync(TSC2102_AUDIO1_CTRL, 0x0100);
+               /* Keyclicks off, soft-stepping at normal rate */
+               tsc2102_write_sync(TSC2102_AUDIO2_CTRL, TSC2102_KEYCLICK_OFF);
+               /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, 0x2800);
+               /* Soft-stepping enabled */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, 0x0000);
+
+               /* PLL generates 44.1 kHz */
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_44K);
+               tsc2102_write_sync(TSC2102_PLL2_CTRL, TSC2102_PLL2_44K);
+
+               /* Codec & DAC power up, virtual ground disabled */
+               tsc2102_write_sync(TSC2102_DAC_POWER_CTRL, TSC2102_DAC_ON);
+       } else {
+               /* All off */
+               tsc2102_write_sync(TSC2102_AUDIO4_CTRL, TSC2102_KEYCLICK_OFF);
+               tsc2102_write_sync(TSC2102_PLL1_CTRL, TSC2102_PLL1_OFF);
+       }
+
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_dac_power);
+
+void tsc2102_set_i2s_master(int state)
+{
+       uint16_t val;
+       spin_lock(&tsc.lock_sync);
+
+       val = tsc2102_read_sync(TSC2102_AUDIO3_CTRL);
+
+       if (state)
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val | TSC2102_SLVMS);
+       else
+               tsc2102_write_sync(TSC2102_AUDIO3_CTRL, val & ~TSC2102_SLVMS);
+
+       spin_unlock(&tsc.lock_sync);
+}
+EXPORT_SYMBOL_GPL(tsc2102_set_i2s_master);
+
+#endif /* CONFIG_SND_OMAP_TSC2101 */
+
+static int tsc2102_configure(struct tsc2102_dev *dev)
+{
+       /* Reset the chip */
+       tsc2102_write_sync(TSC2102_TS_RESET_CTRL, TSC2102_RESET);
+
+       /* Reference mode, 100 usec delay, 1.25 V reference */
+       if (dev->pdata->use_internal)
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_INT_REF);
+       else
+               tsc2102_write_sync(TSC2102_TS_REF_CTRL, TSC2102_ADC_EXT_REF);
+
+       /* 84 usec precharge time, 32 usec sense time */
+       tsc2102_write_sync(TSC2102_TS_CONFIG_CTRL, TSC2102_CONFIG_TIMES);
+
+       /* PINT/DAV acts as DAV */
+       tsc2102_write_sync(TSC2102_TS_STATUS_CTRL, TSC2102_ADC_DAV);
+
+       tsc2102_mode(dev);
+       mod_timer(&dev->mode_timer, jiffies +
+                       msecs_to_jiffies(dev->mode_msecs));
+       return 0;
+}
+
+/*
+ * Retrieves chip revision.  Should be always 1.
+ */
+int tsc2102_get_revision(void)
+{
+       return tsc2102_read_sync(TSC2102_AUDIO3_CTRL) & 7;
+}
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but doesn't sleep until the sound has
+ * finished.
+ */
+void tsc2102_keyclick(int amplitude, int freq, int length)
+{
+       u16 val;
+       spin_lock(&tsc.lock_sync);
+       val = tsc2102_read_sync(TSC2102_AUDIO2_CTRL);
+       val &= 0x800f;
+
+       /* Set amplitude */
+       switch (amplitude) {
+       case 1:
+               val |= 4 << 12;
+               break;
+       case 2:
+               val |= 7 << 12;
+               break;
+       default:
+               break;
+       }
+
+       /* Frequency */
+       val |= (freq & 0x7) << 8;
+
+       /* Round to nearest supported length */
+       if (length > 20)
+               val |= 4 << 4;
+       else if (length > 6)
+               val |= 3 << 4;
+       else if (length > 4)
+               val |= 2 << 4;
+       else if (length > 2)
+               val |= 1 << 4;
+
+       /* Enable keyclick */
+       val |= 0x8000;
+
+       tsc2102_write_sync(TSC2102_AUDIO2_CTRL, val);
+       spin_unlock(&tsc.lock_sync);
+}
+
+#ifdef CONFIG_HWMON
+#define TSC2102_INPUT(devname, field)  \
+static ssize_t show_ ## devname(struct device *dev,    \
+               struct device_attribute *devattr, char *buf)    \
+{      \
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);    \
+       int value = devhwmon->field;    \
+       return sprintf(buf, "%i\n", value);     \
+}      \
+static DEVICE_ATTR(devname ## _input, S_IRUGO, show_ ## devname, NULL);
+
+TSC2102_INPUT(in0, bat[0])
+TSC2102_INPUT(in1, bat[1])
+TSC2102_INPUT(in2, aux[0])
+TSC2102_INPUT(in3, temp[0])
+TSC2102_INPUT(in4, temp[1])
+
+static ssize_t show_temp1(struct device *dev,
+               struct device_attribute *devattr, char *buf)
+{
+       struct tsc2102_dev *devhwmon = dev_get_drvdata(dev);
+       int t1, t2;
+       int value, diff;
+
+       t1 = devhwmon->temp[0];
+       t2 = devhwmon->temp[1];
+
+       /*
+        * Use method #2 (differential) to calculate current temperature.
+        * The difference between TEMP2 and TEMP1 input values is
+        * multiplied by a constant to obtain current temperature.
+        * To find this constant we use the values measured at 25 C as
+        * thermometer calibration data.
+        *
+        * 298150 is 25 degrees Celcius represented in Kelvins and
+        * multiplied by 1000 for fixed point precision (273.15 + 25).
+        * 273150 is zero degrees Celcius.
+        */
+       diff = devhwmon->pdata->temp_at25c[1] - devhwmon->pdata->temp_at25c[0];
+       BUG_ON(diff == 0);
+       value = (t2 - t1) * 298150 / diff;      /* This is in Kelvins now */
+
+       t1 = value - 273150;                    /* Celcius millidegree */
+       return sprintf(buf, "%i\n", t1);
+}
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1, NULL);
+#endif /* CONFIG_HWMON */
+
+#ifdef CONFIG_APM
+static void tsc2102_get_power_status(struct apm_power_info *info)
+{
+       tsc.pdata->apm_report(info, tsc.bat);
+}
+#endif
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc2102_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       del_timer(&dev->mode_timer);
+       del_timer(&dev->ts_timer);
+
+       if (dev->pendown && dev->touch_cb)
+               dev->touch_cb(0);
+
+       /* Abort current conversion and power down the ADC */
+       tsc2102_write_sync(TSC2102_TS_ADC_CTRL, TSC2102_ADC_ADST);
+
+       dev->spi->dev.power.power_state = state;
+
+       spin_unlock(&dev->lock_sync);
+       return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc2102_resume(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+       int err;
+
+       if (!dev)
+               return 0;
+
+       spin_lock(&dev->lock_sync);
+
+       dev->spi->dev.power.power_state = PMSG_ON;
+
+       dev->state = 0;
+       dev->pendown = 0;
+
+       err = tsc2102_configure(dev);
+
+       spin_unlock(&dev->lock_sync);
+       return err;
+}
+#else
+#define tsc2102_suspend        NULL
+#define tsc2102_resume NULL
+#endif
+
+static struct platform_device tsc2102_ts_device = {
+       .name           = "tsc2102-ts",
+       .id             = -1,
+};
+
+static struct platform_device tsc2102_alsa_device = {
+       .name           = "tsc2102-alsa",
+       .id             = -1,
+};
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+       struct tsc2102_config *pdata = spi->dev.platform_data;
+       struct spi_transfer *spi_buffer;
+       int err = 0;
+
+       if (!pdata) {
+               printk(KERN_ERR "TSC2102: Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!spi->irq) {
+               printk(KERN_ERR "TSC2102: Invalid irq value\n");
+               return -ENOENT;
+       }
+
+       tsc.pdata = pdata;
+       tsc.state = 0;
+       tsc.pendown = 0;
+       tsc.data_pending = 0;
+       tsc.ts_msecs = 20;
+       tsc.mode_msecs = 1000;
+       tsc.spi = spi;
+
+       /* Allocate enough struct spi_transfer's for all requests */
+       spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+       if (!spi_buffer) {
+               printk(KERN_ERR "TSC2102: No memory for SPI buffers\n");
+               return -ENOMEM;
+       }
+
+       tsc.transfers = spi_buffer;
+       tsc2102_request_alloc(&tsc, &tsc.req_adc, 0, 4, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_status, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_pressure, 0, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_stopadc, 1, 1, &spi_buffer);
+       tsc2102_request_alloc(&tsc, &tsc.req_mode, 1, 1, &spi_buffer);
+
+       spin_lock_init(&tsc.lock);
+       spin_lock(&tsc.lock_sync);
+
+       /* Get the BCLK - assuming the rate is at 12000000 */
+       tsc.bclk_ck = clk_get(0, "bclk");
+       if (!tsc.bclk_ck) {
+               printk(KERN_ERR "Unable to get the clock BCLK\n");
+               err = -EPERM;
+               goto done;
+       }
+
+       clk_enable(tsc.bclk_ck);
+
+       if (request_irq(spi->irq, tsc2102_handler, IRQF_SAMPLE_RANDOM |
+                               IRQF_TRIGGER_FALLING, "tsc2102", &tsc)) {
+               printk(KERN_ERR "Could not allocate touchscreen IRQ!\n");
+               err = -EINVAL;
+               goto err_clk;
+       }
+
+       setup_timer(&tsc.ts_timer,
+                       tsc2102_pressure, (unsigned long) &tsc);
+       setup_timer(&tsc.mode_timer,
+                       tsc2102_mode_timer, (unsigned long) &tsc);
+
+       /* Set up the communication bus */
+       dev_set_drvdata(&spi->dev, &tsc);
+       spi->dev.power.power_state = PMSG_ON;
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       err = spi_setup(spi);
+       if (err)
+               goto err_timer;
+
+       /* Now try to detect the chip, make first contact */
+       if (tsc2102_get_revision() != 0x1) {
+               printk(KERN_ERR "No TI TSC2102 chip found!\n");
+               goto err_timer;
+       }
+
+       err = tsc2102_configure(&tsc);
+       if (err)
+               goto err_timer;
+
+       /* Register devices controlled by TSC 2102 */
+       tsc2102_ts_device.dev.platform_data = pdata;
+       tsc2102_ts_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_ts_device);
+       if (err)
+               goto err_timer;
+
+       tsc2102_alsa_device.dev.platform_data = pdata->alsa_config;
+       tsc2102_alsa_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc2102_alsa_device);
+       if (err)
+               goto err_ts;
+
+#ifdef CONFIG_HWMON
+       tsc.hwmondev = hwmon_device_register(&spi->dev);
+       if (IS_ERR(tsc.hwmondev)) {
+               printk(KERN_ERR "tsc2102_hwmon: Device registration failed\n");
+               err = PTR_ERR(tsc.hwmondev);
+               goto err_alsa;
+       }
+
+       if (pdata->monitor & TSC_BAT1)
+               err |= device_create_file(&spi->dev, &dev_attr_in0_input);
+       if (pdata->monitor & TSC_BAT2)
+               err |= device_create_file(&spi->dev, &dev_attr_in1_input);
+       if (pdata->monitor & TSC_AUX)
+               err |= device_create_file(&spi->dev, &dev_attr_in2_input);
+       if (pdata->monitor & TSC_TEMP) {
+               err |= device_create_file(&spi->dev, &dev_attr_temp1_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in3_input);
+               err |= device_create_file(&spi->dev, &dev_attr_in4_input);
+       }
+
+       if (err)
+               printk(KERN_ERR "tsc2102_hwmon: Creating one or more "
+                               "attribute files failed\n");
+       err = 0;        /* Not fatal */
+#endif
+
+#ifdef CONFIG_APM
+       if (pdata->apm_report)
+               apm_get_power_status = tsc2102_get_power_status;
+#endif
+
+       if (!err)
+               goto done;
+
+err_alsa:
+       platform_device_unregister(&tsc2102_alsa_device);
+err_ts:
+       platform_device_unregister(&tsc2102_ts_device);
+err_timer:
+       del_timer(&tsc.ts_timer);
+       del_timer(&tsc.mode_timer);
+       dev_set_drvdata(&spi->dev, NULL);
+err_clk:
+       clk_disable(tsc.bclk_ck);
+       clk_put(tsc.bclk_ck);
+done:
+       spin_unlock(&tsc.lock_sync);
+       return err;
+}
+
+static int tsc2102_remove(struct spi_device *spi)
+{
+       struct tsc2102_dev *dev = dev_get_drvdata(&spi->dev);
+
+       spin_lock(&dev->lock_sync);
+
+       platform_device_unregister(&tsc2102_ts_device);
+       platform_device_unregister(&tsc2102_alsa_device);
+
+       dev_set_drvdata(&spi->dev, NULL);
+
+       /* Release the BCLK */
+       clk_disable(dev->bclk_ck);
+       clk_put(dev->bclk_ck);
+
+       del_timer(&tsc.mode_timer);
+       del_timer(&tsc.ts_timer);
+
+       kfree(tsc.transfers);
+
+#ifdef CONFIG_HWMON
+       hwmon_device_unregister(dev->hwmondev);
+#endif
+
+#ifdef CONFIG_APM
+       apm_get_power_status = 0;
+#endif
+
+       spin_unlock(&dev->lock_sync);
+
+       return 0;
+}
+
+static struct spi_driver tsc2102_driver = {
+       .probe          = tsc2102_probe,
+       .remove         = tsc2102_remove,
+       .suspend        = tsc2102_suspend,
+       .resume         = tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102",
+               .owner  = THIS_MODULE,
+               .bus    = &spi_bus_type,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC2102 driver initializing\n";
+
+static int __init tsc2102_init(void)
+{
+       printk(banner);
+       return spi_register_driver(&tsc2102_driver);
+}
+
+static void __exit tsc2102_exit(void)
+{
+       spi_unregister_driver(&tsc2102_driver);
+}
+
+module_init(tsc2102_init);
+module_exit(tsc2102_exit);
+
+EXPORT_SYMBOL(tsc2102_read_sync);
+EXPORT_SYMBOL(tsc2102_reads_sync);
+EXPORT_SYMBOL(tsc2102_write_sync);
+EXPORT_SYMBOL(tsc2102_keyclick);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC2102 chips.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc210x.c b/drivers/spi/tsc210x.c
new file mode 100644 (file)
index 0000000..1d2ac94
--- /dev/null
@@ -0,0 +1,1262 @@
+/*
+ * tsc210x.c - TSC2101/2102/... driver core
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/autoconf.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc210x.h>
+
+
+/* NOTE:  It should be straightforward to make this driver framework handle
+ * tsc2100 and tsc2111 chips, and maybe others too.  The main differences
+ * are in the audio codec capabilities, but there are also some differences
+ * in how the various sensors (including touchscreen) are handled.
+ */
+
+/* Bit field definitions for chip registers */
+
+/* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_TS_CONTROL         0x8bf4
+/* Scan BAT1, BAT2, AUX1, AUX2, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_SCAN_CONTROL       0x2ff4
+/* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_T1_CONTROL         0x2bf4
+/* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+#define TSC210X_ADC_T2_CONTROL         0x33f4
+/* PINT/DAV acts as DAV */
+#define TSC210X_ADC_DAV                        0x4000
+/* Internal reference, 100 usec delay, 1.25 V reference */
+#define TSC210X_ADC_INT_REF            0x0016
+/* External reference, 100 usec delay, 1.25 V reference */
+#define TSC210X_ADC_EXT_REF            0x0002
+/* 84 usec precharge time, 32 usec sense time */
+#define TSC210X_CONFIG_TIMES           0x0008
+/* The reset sequence */
+#define TSC210X_RESET                  0xbb00
+/* Pen Status bit */
+#define TSC210X_ADC_PSTCM              (1 << 15)
+/* A/D Status bit */
+#define TSC210X_ADC_ADST               (1 << 14)
+/* (At least) One of X, Y, Z1, Z2 contains data */
+#define TSC210X_TS_DAV                 0x0780
+/* (At least) One of BAT1, BAT2, AUX1, AUX2 contains data */
+#define TSC210X_PS_DAV                 0x0078
+/* TEMP1 contains data */
+#define TSC210X_T1_DAV                 0x0004
+/* TEMP2 contains data */
+#define TSC210X_T2_DAV                 0x0002
+#define TSC2101_DAC_ON                 0x0000
+#define TSC2101_DAC_OFF                        0xe7fc
+#define TSC2102_DAC_ON                 0x3ba0
+#define TSC2102_DAC_OFF                        0xafa0
+#define TSC210X_FS44K                  (1 << 13)
+#define TSC210X_PLL1_OFF               0x0000
+#define TSC210X_PLL1_44K               0x811c
+#define TSC210X_PLL1_48K               0x8120
+#define TSC210X_PLL2_44K               (5462 << 2)
+#define TSC210X_PLL2_48K               (1920 << 2)
+#define TSC210X_SLVMS                  (1 << 11)
+#define TSC210X_DEEMPF                 (1 << 0)
+#define TSC2102_BASSBC                 (1 << 1)
+#define TSC210X_KEYCLICK_OFF           0x0000
+
+#define CS_CHANGE(val)                 0
+
+struct tsc210x_spi_req {
+       struct spi_device *dev;
+       u16 command;
+       u16 data;
+       struct spi_message message;
+};
+
+struct tsc210x_dev {
+       enum tsc_type {
+               tsc2101,
+               tsc2102,
+       } kind;
+       struct tsc210x_config *pdata;
+       struct clk *bclk_ck;
+
+       struct workqueue_struct *queue;
+       struct delayed_work ts_worker;          /* Poll-wait for PEN UP */
+       struct delayed_work sensor_worker;      /* Scan the ADC inputs */
+       struct mutex queue_lock;
+       struct completion data_avail;
+
+       tsc210x_touch_t touch_cb;
+       void *touch_cb_ctx;
+
+       tsc210x_coords_t coords_cb;
+       void *coords_cb_ctx;
+
+       tsc210x_ports_t ports_cb;
+       void *ports_cb_ctx;
+
+       tsc210x_temp_t temp1_cb;
+       void *temp2_cb_ctx;
+
+       tsc210x_temp_t temp2_cb;
+       void *temp1_cb_ctx;
+
+       struct spi_device *spi;
+       struct spi_transfer *transfers;
+       struct tsc210x_spi_req req_adc;
+       struct tsc210x_spi_req req_status;
+       struct tsc210x_spi_req req_mode;
+       struct tsc210x_spi_req req_stop;
+
+       int pendown;
+       int flushing;                   /* Queue flush in progress */
+       u16 status;
+       u16 adc_data[4];
+       int bat[2], aux[2], temp[2];
+};
+
+static struct {
+       unsigned int ts_msecs;          /* Interval for .ts_timer */
+       unsigned int mode_msecs;        /* Interval for .mode_timer */
+} settings;
+
+module_param_named(touch_check_msecs, settings.ts_msecs, uint, 0);
+MODULE_PARM_DESC(touch_check_msecs, "Pen-up polling interval in msecs");
+
+module_param_named(sensor_scan_msecs, settings.mode_msecs, uint, 0);
+MODULE_PARM_DESC(sensor_scan_msecs, "Temperature & battery scan interval");
+
+int tsc210x_write_sync(struct tsc210x_dev *dev,
+               int page, u8 address, u16 data)
+{
+       static struct tsc210x_spi_req req;
+       static struct spi_transfer transfer[2];
+       int ret;
+
+       spi_message_init(&req.message);
+
+       /* Address */
+       req.command = (page << 11) | (address << 5);
+       transfer[0].tx_buf = &req.command;
+       transfer[0].rx_buf = NULL;
+       transfer[0].len = 2;
+       spi_message_add_tail(&transfer[0], &req.message);
+
+       /* Data */
+       transfer[1].tx_buf = &data;
+       transfer[1].rx_buf = NULL;
+       transfer[1].len = 2;
+       transfer[1].cs_change = CS_CHANGE(1);
+       spi_message_add_tail(&transfer[1], &req.message);
+
+       ret = spi_sync(dev->spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+       if (ret)
+               dev_dbg(&dev->spi->dev, "write_sync --> %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(tsc210x_write_sync);
+
+int tsc210x_reads_sync(struct tsc210x_dev *dev,
+               int page, u8 startaddress, u16 *data, int numregs)
+{
+       static struct tsc210x_spi_req req;
+       static struct spi_transfer transfer[6];
+       int ret, i, j;
+
+       if (numregs + 1 > ARRAY_SIZE(transfer))
+               return -EINVAL;
+
+       spi_message_init(&req.message);
+       i = 0;
+       j = 0;
+
+       /* Address */
+       req.command = 0x8000 | (page << 11) | (startaddress << 5);
+       transfer[i].tx_buf = &req.command;
+       transfer[i].rx_buf = NULL;
+       transfer[i].len = 2;
+       spi_message_add_tail(&transfer[i ++], &req.message);
+
+       /* Data */
+       while (j < numregs) {
+               transfer[i].tx_buf = NULL;
+               transfer[i].rx_buf = &data[j ++];
+               transfer[i].len = 2;
+               transfer[i].cs_change = CS_CHANGE(j == numregs);
+               spi_message_add_tail(&transfer[i ++], &req.message);
+       }
+
+       ret = spi_sync(dev->spi, &req.message);
+       if (!ret && req.message.status)
+               ret = req.message.status;
+       if (ret)
+               dev_dbg(&dev->spi->dev, "reads_sync --> %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(tsc210x_reads_sync);
+
+int tsc210x_read_sync(struct tsc210x_dev *dev, int page, u8 address)
+{
+       u16 ret;
+       int status;
+
+       status = tsc210x_reads_sync(dev, page, address, &ret, 1);
+       return status ? : ret;
+}
+EXPORT_SYMBOL(tsc210x_read_sync);
+
+
+static void tsc210x_submit_async(struct tsc210x_spi_req *spi)
+{
+       int ret;
+
+       ret = spi_async(spi->dev, &spi->message);
+       if (ret)
+               dev_dbg(&spi->dev->dev, "%s: error %i in SPI request\n",
+                               __FUNCTION__, ret);
+}
+
+static void tsc210x_request_alloc(struct tsc210x_dev *dev,
+               struct tsc210x_spi_req *spi, int direction,
+               int page, u8 startaddress, int numregs, u16 *data,
+               void (*complete)(struct tsc210x_dev *context),
+               struct spi_transfer **transfer)
+{
+       spi->dev = dev->spi;
+
+       if (direction == 1)     /* Write */
+               numregs = 2;
+       else                    /* Read */
+               numregs += 1;
+
+       spi_message_init(&spi->message);
+       spi->message.complete = (void (*)(void *)) complete;
+       spi->message.context = dev;
+
+       /* Address */
+       spi->command = (page << 11) | (startaddress << 5);
+       if (direction != 1)
+               spi->command |= 1 << 15;
+
+       (*transfer)->tx_buf = &spi->command;
+       (*transfer)->rx_buf = NULL;
+       (*transfer)->len = 2;
+       spi_message_add_tail((*transfer) ++, &spi->message);
+
+       /* Data */
+       while (-- numregs) {
+               if (direction == 1)
+                       (*transfer)->tx_buf = &spi->data;
+               else
+                       (*transfer)->rx_buf = data++;
+               (*transfer)->len = 2;
+               (*transfer)->cs_change = CS_CHANGE(numregs != 1);
+               spi_message_add_tail((*transfer) ++, &spi->message);
+       }
+}
+
+#define tsc210x_cb_register_func(cb, cb_t)     \
+int tsc210x_ ## cb(struct device *dev, cb_t handler, void *context)    \
+{      \
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev); \
+       \
+       /* Lock the module */   \
+       if (handler && !tsc->cb)        \
+               if (!try_module_get(THIS_MODULE)) {     \
+                       dev_err(dev, "Failed to get TSC module\n");     \
+               }       \
+       if (!handler && tsc->cb)        \
+               module_put(THIS_MODULE);        \
+       \
+       tsc->cb = handler;      \
+       tsc->cb ## _ctx = context;      \
+       return 0;       \
+} \
+EXPORT_SYMBOL(tsc210x_ ## cb);
+
+tsc210x_cb_register_func(touch_cb, tsc210x_touch_t)
+tsc210x_cb_register_func(coords_cb, tsc210x_coords_t)
+tsc210x_cb_register_func(ports_cb, tsc210x_ports_t)
+tsc210x_cb_register_func(temp1_cb, tsc210x_temp_t)
+tsc210x_cb_register_func(temp2_cb, tsc210x_temp_t)
+
+#ifdef DEBUG
+static void tsc210x_print_dav(struct tsc210x_dev *dev)
+{
+       int status = tsc210x_read_sync(dev, TSC210X_TS_STATUS_CTRL);
+
+       if (status < 0) {
+               dev_dbg(&dev->spi->dev, "status %d\n", status);
+               return;
+       }
+
+       if (!(status & 0x0fff))
+               return;
+
+       dev_dbg(&dev->spi->dev, "data in %s%s%s%s%s%s%s%s%s%s%s\n",
+               (status & 0x0400) ? " X" : "",
+               (status & 0x0200) ? " Y" : "",
+               (status & 0x0100) ? " Z1" : "",
+               (status & 0x0080) ? " Z2" : "",
+               (status & 0x0040) ? " BAT1" : "",
+               (status & 0x0020) ? " BAT2" : "",
+               (status & 0x0010) ? " AUX1" : "",
+               (status & 0x0008) ? " AUX2" : "",
+               (status & 0x0004) ? " TEMP1" : "",
+               (status & 0x0002) ? " TEMP2" : "",
+               (status & 0x0001) ? " KP" : "");
+}
+#endif
+
+static void tsc210x_complete_dummy(struct tsc210x_dev *dev)
+{
+}
+
+static inline void tsc210x_touchscreen_mode(struct tsc210x_dev *dev)
+{
+       /* Scan X, Y, Z1, Z2, chip controlled, 12-bit, 16 samples, 500 usec */
+       dev->req_mode.data = TSC210X_ADC_TS_CONTROL;
+       tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_portscan_mode(struct tsc210x_dev *dev)
+{
+       /* Scan BAT1, BAT2, AUX1, AUX2, 12-bit, 16 samples, 500 usec */
+       dev->req_mode.data = TSC210X_ADC_SCAN_CONTROL;
+       tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_temp1_mode(struct tsc210x_dev *dev)
+{
+       /* Scan TEMP1, 12-bit, 16 samples, 500 usec */
+       dev->req_mode.data = TSC210X_ADC_T1_CONTROL;
+       tsc210x_submit_async(&dev->req_mode);
+}
+
+static inline void tsc210x_temp2_mode(struct tsc210x_dev *dev)
+{
+       /* Scan TEMP2, 12-bit, 16 samples, 500 usec */
+       dev->req_mode.data = TSC210X_ADC_T2_CONTROL;
+       tsc210x_submit_async(&dev->req_mode);
+}
+
+/* Abort current conversion if any */
+static void tsc210x_new_mode(struct tsc210x_dev *dev)
+{
+       dev->req_stop.data = TSC210X_ADC_ADST;
+       tsc210x_submit_async(&dev->req_stop);
+}
+
+static void tsc210x_queue_scan(struct tsc210x_dev *dev)
+{
+       if (dev->pdata->monitor)
+               if (!queue_delayed_work(dev->queue,
+                               &dev->sensor_worker,
+                               msecs_to_jiffies(settings.mode_msecs)))
+                       dev_err(&dev->spi->dev,
+                                       "%s: can't queue measurements\n",
+                                       __FUNCTION__);
+}
+
+static void tsc210x_queue_penup(struct tsc210x_dev *dev)
+{
+       if (!queue_delayed_work(dev->queue,
+                       &dev->ts_worker,
+                       msecs_to_jiffies(settings.ts_msecs)))
+               dev_err(&dev->spi->dev,
+                               "%s: can't queue pen-up poll\n",
+                               __FUNCTION__);
+}
+
+static void tsc210x_status_report(struct tsc210x_dev *dev)
+{
+       /*
+        * Read all converted data from corresponding registers
+        * so that the ADC can move on to a new conversion.
+        */
+       if (dev->status & TSC210X_TS_DAV) {
+               if (!dev->pendown && !dev->flushing) {
+                       dev->pendown = 1;
+                       if (dev->touch_cb)
+                               dev->touch_cb(dev->touch_cb_ctx, 1);
+
+                       tsc210x_queue_penup(dev);
+               }
+
+               tsc210x_submit_async(&dev->req_adc);
+       }
+
+       if (dev->status & (TSC210X_PS_DAV | TSC210X_T1_DAV | TSC210X_T2_DAV))
+               complete(&dev->data_avail);
+}
+
+static void tsc210x_data_report(struct tsc210x_dev *dev)
+{
+       u16 adc_data[4];
+
+       if (dev->status & TSC210X_PS_DAV) {
+               tsc210x_reads_sync(dev, TSC210X_TS_BAT1, adc_data, 4);
+               /* NOTE: reads_sync() could fail */
+
+               dev->bat[0] = adc_data[0];
+               dev->bat[1] = adc_data[1];
+               dev->aux[0] = adc_data[2];
+               dev->aux[1] = adc_data[3];
+               if (dev->ports_cb)
+                       dev->ports_cb(dev->ports_cb_ctx, dev->bat, dev->aux);
+       }
+
+       if (dev->status & TSC210X_T1_DAV) {
+               dev->temp[0] = tsc210x_read_sync(dev, TSC210X_TS_TEMP1);
+
+               if (dev->temp[0] >= 0 && dev->temp1_cb)
+                       dev->temp1_cb(dev->temp1_cb_ctx, dev->temp[0]);
+       }
+
+       if (dev->status & TSC210X_T2_DAV) {
+               dev->temp[1] = tsc210x_read_sync(dev, TSC210X_TS_TEMP2);
+
+               if (dev->temp[1] >= 0 && dev->temp2_cb)
+                       dev->temp2_cb(dev->temp2_cb_ctx, dev->temp[1]);
+       }
+}
+
+static void tsc210x_coords_report(struct tsc210x_dev *dev)
+{
+       if (dev->coords_cb)
+               dev->coords_cb(dev->coords_cb_ctx,
+                               dev->adc_data[0], dev->adc_data[1],
+                               dev->adc_data[2], dev->adc_data[3]);
+}
+
+/*
+ * There are at least three ways to check for pen-up:
+ *     - the PINT/DAV pin state,
+ *     - reading PSTCM bit in ADC Control register (D15, offset 0x00),
+ *     - reading ADST bit in ADC Control register (D14, offset 0x00),
+ *             ADC idle would indicate no screen touch.
+ * Unfortunately none of them seems to be 100% accurate and you will
+ * find they are totally inconsistent, i.e. you get to see any arbitrary
+ * combination of values in these three bits.  So we will busy-wait
+ * for a moment when the latter two indicate a pen-up, using a queue,
+ * before we report a pen-up.
+ */
+static void tsc210x_pressure(struct work_struct *work)
+{
+       struct tsc210x_dev *dev =
+               container_of(work, struct tsc210x_dev, ts_worker.work);
+       int adc_status;
+
+       WARN_ON(!dev->pendown);
+
+       adc_status = tsc210x_read_sync(dev, TSC210X_TS_ADC_CTRL);
+       if (adc_status < 0) {
+               dev_dbg(&dev->spi->dev, "pressure, err %d\n", adc_status);
+               return;
+       }
+
+       if ((adc_status & TSC210X_ADC_PSTCM) != 0
+                       || !(adc_status & TSC210X_ADC_ADST))
+               tsc210x_queue_penup(dev);
+       else {
+               dev->pendown = 0;
+               if (dev->touch_cb)
+                       dev->touch_cb(dev->touch_cb_ctx, 0);
+       }
+}
+
+static void tsc210x_wait_data(struct tsc210x_dev *dev)
+{
+       wait_for_completion(&dev->data_avail);
+
+       tsc210x_data_report(dev);
+}
+
+static void tsc210x_input_scan(struct work_struct *work)
+{
+       struct tsc210x_dev *dev = (struct tsc210x_dev *)
+               container_of(work, struct tsc210x_dev, sensor_worker.work);
+
+       tsc210x_new_mode(dev);
+
+       if (dev->pdata->monitor &
+                       (TSC_BAT1 | TSC_BAT2 | TSC_AUX1 | TSC_AUX2)) {
+               tsc210x_portscan_mode(dev);
+               tsc210x_wait_data(dev);
+       }
+
+       if (dev->pdata->monitor & TSC_TEMP) {
+               tsc210x_temp1_mode(dev);
+               tsc210x_wait_data(dev);
+
+               tsc210x_temp2_mode(dev);
+               tsc210x_wait_data(dev);
+       }
+
+       tsc210x_touchscreen_mode(dev);
+
+       mutex_lock(&dev->queue_lock);
+       if (!dev->flushing)
+               tsc210x_queue_scan(dev);
+       mutex_unlock(&dev->queue_lock);
+}
+
+/* ADC has finished a new conversion for us.  */
+static irqreturn_t tsc210x_handler(int irq, void *dev_id)
+{
+       struct tsc210x_dev *dev = (struct tsc210x_dev *) dev_id;
+
+       /* See what data became available.  */
+       tsc210x_submit_async(&dev->req_status);
+
+       return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+
+/*
+ * FIXME the audio support shouldn't be included in upstream patches
+ * until it's ready.  They might be better as utility functions linked
+ * with a chip-specific tsc21xx audio module ... e.g. chips with input
+ * channels need more, as will ones with multiple output channels and
+ * so on.  Each of these functions should probably return a fault code,
+ * and will need to be exported so the sound drier can be modular.
+ */
+
+/*
+ * Volume level values should be in the range [0, 127].
+ * Higher values mean lower volume.
+ */
+void tsc210x_set_dac_volume(struct device *dev, u8 left_ch, u8 right_ch)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       if (tsc->kind == tsc2102) {
+               /* All 0's or all 1's */
+               if (left_ch == 0x00 || left_ch == 0x7f)
+                       left_ch ^= 0x7f;
+               if (right_ch == 0x00 || right_ch == 0x7f)
+                       right_ch ^= 0x7f;
+       }
+
+       val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       val &= 0x8080;  /* Preserve mute-bits */
+       val |= (left_ch << 8) | right_ch;
+
+       tsc210x_write_sync(tsc, TSC210X_DAC_GAIN_CTRL, val);
+       /* NOTE: write_sync() could fail */
+}
+
+void tsc210x_set_dac_mute(struct device *dev, int left_ch, int right_ch)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       val &= 0x7f7f;  /* Preserve volume settings */
+       val |= (left_ch << 15) | (right_ch << 7);
+
+       tsc210x_write_sync(tsc, TSC210X_DAC_GAIN_CTRL, val);
+       /* NOTE: write_sync() could fail */
+}
+
+void tsc210x_get_dac_mute(struct device *dev, int *left_ch, int *right_ch)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       val = tsc210x_read_sync(tsc, TSC210X_DAC_GAIN_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       *left_ch = !!(val & (1 << 15));
+       *right_ch = !!(val & (1 << 7));
+}
+
+void tsc210x_set_deemphasis(struct device *dev, int enable)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       val = tsc210x_read_sync(tsc, TSC210X_POWER_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       if (enable)
+               val &= ~TSC210X_DEEMPF;
+       else
+               val |= TSC210X_DEEMPF;
+
+       tsc210x_write_sync(tsc, TSC210X_POWER_CTRL, val);
+       /* NOTE: write_sync() could fail */
+}
+
+void tsc2102_set_bassboost(struct device *dev, int enable)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       val = tsc210x_read_sync(tsc, TSC210X_POWER_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       if (enable)
+               val &= ~TSC2102_BASSBC;
+       else
+               val |= TSC2102_BASSBC;
+
+       tsc210x_write_sync(tsc, TSC210X_POWER_CTRL, val);
+       /* NOTE: write_sync() could fail */
+}
+
+/*     {rate, dsor, fsref}     */
+static const struct tsc210x_rate_info_s tsc2101_rates[] = {
+       /* Fsref / 6.0 */
+       {7350,  7,      1},
+       {8000,  7,      0},
+       /* Fsref / 5.5 */
+       {8018,  6,      1},
+       {8727,  6,      0},
+       /* Fsref / 5.0 */
+       {8820,  5,      1},
+       {9600,  5,      0},
+       /* Fsref / 4.0 */
+       {11025, 4,      1},
+       {12000, 4,      0},
+       /* Fsref / 3.0 */
+       {14700, 3,      1},
+       {16000, 3,      0},
+       /* Fsref / 2.0 */
+       {22050, 2,      1},
+       {24000, 2,      0},
+       /* Fsref / 1.5 */
+       {29400, 1,      1},
+       {32000, 1,      0},
+       /* Fsref */
+       {44100, 0,      1},
+       {48000, 0,      0},
+
+       {0,     0,      0},
+};
+
+/*     {rate, dsor, fsref}     */
+static const struct tsc210x_rate_info_s tsc2102_rates[] = {
+       /* Fsref / 6.0 */
+       {7350,  63,     1},
+       {8000,  63,     0},
+       /* Fsref / 6.0 */
+       {7350,  54,     1},
+       {8000,  54,     0},
+       /* Fsref / 5.0 */
+       {8820,  45,     1},
+       {9600,  45,     0},
+       /* Fsref / 4.0 */
+       {11025, 36,     1},
+       {12000, 36,     0},
+       /* Fsref / 3.0 */
+       {14700, 27,     1},
+       {16000, 27,     0},
+       /* Fsref / 2.0 */
+       {22050, 18,     1},
+       {24000, 18,     0},
+       /* Fsref / 1.5 */
+       {29400, 9,      1},
+       {32000, 9,      0},
+       /* Fsref */
+       {44100, 0,      1},
+       {48000, 0,      0},
+
+       {0,     0,      0},
+};
+
+int tsc210x_set_rate(struct device *dev, int rate)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int i;
+       int val;
+       const struct tsc210x_rate_info_s *rates;
+
+       if (tsc->kind == tsc2101)
+               rates = tsc2101_rates;
+       else
+               rates = tsc2102_rates;
+
+       for (i = 0; rates[i].sample_rate; i ++)
+               if (rates[i].sample_rate == rate)
+                       break;
+       if (rates[i].sample_rate == 0) {
+               dev_err(dev, "Unknown sampling rate %i.0 Hz\n", rate);
+               return -EINVAL;
+       }
+
+       if (tsc->kind == tsc2101) {
+               val = tsc210x_read_sync(tsc, TSC210X_AUDIO1_CTRL);
+               if (val < 0) {
+                       dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+                       return val;
+               }
+               val &= ~((7 << 3) | (7 << 0));
+               val |= rates[i].divisor << 3;
+               val |= rates[i].divisor << 0;
+       } else
+               val = rates[i].divisor;
+
+       tsc210x_write_sync(tsc, TSC210X_AUDIO1_CTRL, val);
+       /* NOTE: write_sync() could fail */
+
+       val = tsc210x_read_sync(tsc, TSC210X_AUDIO3_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return val;
+       }
+
+       if (tsc2102_rates[i].fs_44k) {
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO3_CTRL, val | TSC210X_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc210x_write_sync(tsc, TSC210X_PLL1_CTRL, TSC210X_PLL1_44K);
+               tsc210x_write_sync(tsc, TSC210X_PLL2_CTRL, TSC210X_PLL2_44K);
+       } else {
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO3_CTRL, val & ~TSC210X_FS44K);
+               /* Enable Phase-locked-loop, set up clock dividers */
+               tsc210x_write_sync(tsc, TSC210X_PLL1_CTRL, TSC210X_PLL1_48K);
+               tsc210x_write_sync(tsc, TSC210X_PLL2_CTRL, TSC210X_PLL2_48K);
+       }
+
+       return 0;
+}
+
+/*
+ * Perform basic set-up with default values and power the DAC/ADC on.
+ */
+void tsc210x_dac_power(struct device *dev, int on)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+
+       /* NOTE: write_sync() could fail */
+       if (on) {
+               /* 16-bit words, DSP mode, sample at Fsref */
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO1_CTRL, 0x0100);
+               /* Keyclicks off, soft-stepping at normal rate */
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO2_CTRL, TSC210X_KEYCLICK_OFF);
+               /* 44.1 kHz Fsref, continuous transfer mode, master DAC */
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO3_CTRL, 0x2000);
+               /* Soft-stepping enabled, 1 dB MIX AGC hysteresis */
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO4_CTRL, 0x0000);
+
+               /* PLL generates 44.1 kHz */
+               tsc210x_write_sync(tsc,
+                               TSC210X_PLL1_CTRL, TSC210X_PLL1_44K);
+               tsc210x_write_sync(tsc,
+                               TSC210X_PLL2_CTRL, TSC210X_PLL2_44K);
+
+               /* Codec & DAC power up, virtual ground disabled */
+               tsc210x_write_sync(tsc,
+                               TSC210X_POWER_CTRL, (tsc->kind == tsc2101) ?
+                               TSC2101_DAC_ON : TSC2102_DAC_ON);
+       } else {
+               /* All off */
+               tsc210x_write_sync(tsc,
+                               TSC210X_AUDIO2_CTRL, TSC210X_KEYCLICK_OFF);
+               tsc210x_write_sync(tsc,
+                               TSC210X_PLL1_CTRL, TSC210X_PLL1_OFF);
+#if 0
+               tsc210x_write_sync(tsc,
+                               TSC210X_POWER_CTRL, (tsc->kind == tsc2101) ?
+                               TSC2102_DAC_OFF : TSC2102_DAC_OFF);
+#endif
+       }
+}
+
+void tsc210x_set_i2s_master(struct device *dev, int state)
+{
+       struct tsc210x_dev *tsc = dev_get_drvdata(dev);
+       int val;
+
+       val = tsc210x_read_sync(tsc, TSC210X_AUDIO3_CTRL);
+       if (val < 0) {
+               dev_dbg(dev, "%s, err %d\n", __FUNCTION__, val);
+               return;
+       }
+
+       /* NOTE: write_sync() could fail */
+       if (state)
+               tsc210x_write_sync(tsc, TSC210X_AUDIO3_CTRL,
+                               val | TSC210X_SLVMS);
+       else
+               tsc210x_write_sync(tsc, TSC210X_AUDIO3_CTRL,
+                               val & ~TSC210X_SLVMS);
+}
+#endif /* CONFIG_SOUND */
+
+static int tsc210x_configure(struct tsc210x_dev *dev)
+{
+       /* NOTE: write_sync() could fail */
+
+       /* Reset the chip */
+       tsc210x_write_sync(dev, TSC210X_TS_RESET_CTRL, TSC210X_RESET);
+
+       /* Reference mode */
+       if (dev->pdata->use_internal)
+               tsc210x_write_sync(dev,
+                               TSC210X_TS_REF_CTRL, TSC210X_ADC_INT_REF);
+       else
+               tsc210x_write_sync(dev,
+                               TSC210X_TS_REF_CTRL, TSC210X_ADC_EXT_REF);
+
+       /* Precharge and sense delays, pen touch detection on */
+       tsc210x_write_sync(dev, TSC210X_TS_CONFIG_CTRL, TSC210X_CONFIG_TIMES);
+
+       /* PINT/DAV acts as DAV */
+       tsc210x_write_sync(dev, TSC210X_TS_STATUS_CTRL, TSC210X_ADC_DAV);
+
+       tsc210x_queue_scan(dev);
+       return 0;
+}
+
+void tsc210x_keyclick(struct tsc210x_dev *dev,
+               int amplitude, int freq, int length)
+{
+       int val;
+
+       val = tsc210x_read_sync(dev, TSC210X_AUDIO2_CTRL);
+       if (val < 0) {
+               dev_dbg(&dev->spi->dev, "%s, err %d\n",
+                               __FUNCTION__, val);
+               return;
+       }
+       val &= 0x800f;
+
+       /* Set amplitude */
+       switch (amplitude) {
+       case 1:
+               val |= 4 << 12;
+               break;
+       case 2:
+               val |= 7 << 12;
+               break;
+       default:
+               break;
+       }
+
+       /* Frequency */
+       val |= (freq & 0x7) << 8;
+
+       /* Round to nearest supported length */
+       if (dev->kind == tsc2101)
+               val = (min(length - 1, 31) >> 1) << 4;
+       else {
+               if (length > 20)
+                       val |= 4 << 4;
+               else if (length > 6)
+                       val |= 3 << 4;
+               else if (length > 4)
+                       val |= 2 << 4;
+               else if (length > 2)
+                       val |= 1 << 4;
+       }
+
+       /* Enable keyclick */
+       val |= 0x8000;
+
+       /* NOTE: write_sync() could fail */
+       tsc210x_write_sync(dev, TSC210X_AUDIO2_CTRL, val);
+}
+EXPORT_SYMBOL(tsc210x_keyclick);
+
+#ifdef CONFIG_PM
+/*
+ * Suspend the chip.
+ */
+static int
+tsc210x_suspend(struct spi_device *spi, pm_message_t state)
+{
+       struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+
+       if (!dev)
+               return -ENODEV;
+
+       /* Stop the inputs scan loop */
+       mutex_lock(&dev->queue_lock);
+       dev->flushing = 1;
+       cancel_delayed_work(&dev->sensor_worker);
+       mutex_unlock(&dev->queue_lock);
+       flush_workqueue(dev->queue);
+
+       /* Wait until pen-up happens */
+       while (dev->pendown)
+               flush_workqueue(dev->queue);
+
+       /* Abort current conversion and power down the ADC */
+       tsc210x_write_sync(dev, TSC210X_TS_ADC_CTRL, TSC210X_ADC_ADST);
+       /* NOTE: write_sync() could fail */
+
+       return 0;
+}
+
+/*
+ * Resume chip operation.
+ */
+static int tsc210x_resume(struct spi_device *spi)
+{
+       struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+       int err;
+
+       if (!dev)
+               return 0;
+
+       mutex_lock(&dev->queue_lock);
+       err = tsc210x_configure(dev);
+
+       dev->flushing = 0;
+       mutex_unlock(&dev->queue_lock);
+
+       return err;
+}
+#else
+#define tsc210x_suspend        NULL
+#define tsc210x_resume NULL
+#endif
+
+/* REVISIT don't make these static */
+static struct platform_device tsc210x_ts_device = {
+       .name           = "tsc210x-ts",
+       .id             = -1,
+};
+
+static struct platform_device tsc210x_hwmon_device = {
+       .name           = "tsc210x-hwmon",
+       .id             = -1,
+};
+
+static struct platform_device tsc210x_alsa_device = {
+       .name           = "tsc210x-alsa",
+       .id             = -1,
+};
+
+static int tsc210x_probe(struct spi_device *spi, enum tsc_type type)
+{
+       struct tsc210x_config *pdata = spi->dev.platform_data;
+       struct spi_transfer *spi_buffer;
+       struct tsc210x_dev *dev;
+       int reg;
+       int err = 0;
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "Platform data not supplied\n");
+               return -ENOENT;
+       }
+
+       if (!spi->irq) {
+               dev_dbg(&spi->dev, "Invalid irq value\n");
+               return -EINVAL;
+       }
+
+       dev = (struct tsc210x_dev *)
+               kzalloc(sizeof(struct tsc210x_dev), GFP_KERNEL);
+       if (!dev) {
+               dev_dbg(&spi->dev, "No memory\n");
+               return -ENOMEM;
+       }
+
+       dev->pdata = pdata;
+       dev->pendown = 0;
+       dev->spi = spi;
+       dev->kind = type;
+       dev->queue = create_singlethread_workqueue(spi->dev.driver->name);
+       if (!dev->queue) {
+               dev_dbg(&spi->dev, "Can't make a workqueue\n");
+               err = -ENOMEM;
+               goto err_queue;
+       }
+
+       mutex_init(&dev->queue_lock);
+       init_completion(&dev->data_avail);
+
+       /* Allocate enough struct spi_transfer's for all requests */
+       spi_buffer = kzalloc(sizeof(struct spi_transfer) * 16, GFP_KERNEL);
+       if (!spi_buffer) {
+               dev_dbg(&spi->dev, "No memory for SPI buffers\n");
+               err = -ENOMEM;
+               goto err_buffers;
+       }
+
+       dev->transfers = spi_buffer;
+       tsc210x_request_alloc(dev, &dev->req_adc, 0,
+                       TSC210X_TS_X, 4, dev->adc_data,
+                       tsc210x_coords_report, &spi_buffer);
+       tsc210x_request_alloc(dev, &dev->req_status, 0,
+                       TSC210X_TS_STATUS_CTRL, 1, &dev->status,
+                       tsc210x_status_report, &spi_buffer);
+       tsc210x_request_alloc(dev, &dev->req_mode, 1,
+                       TSC210X_TS_ADC_CTRL, 1, NULL,
+                       tsc210x_complete_dummy, &spi_buffer);
+       tsc210x_request_alloc(dev, &dev->req_stop, 1,
+                       TSC210X_TS_ADC_CTRL, 1, NULL,
+                       tsc210x_complete_dummy, &spi_buffer);
+
+       if (pdata->bclk) {
+               /* Get the BCLK */
+               dev->bclk_ck = clk_get(&spi->dev, pdata->bclk);
+               if (IS_ERR(dev->bclk_ck)) {
+                       err = PTR_ERR(dev->bclk_ck);
+                       dev_dbg(&spi->dev, "Unable to get '%s': %i\n",
+                                       pdata->bclk, err);
+                       goto err_clk;
+               }
+
+               clk_enable(dev->bclk_ck);
+       }
+
+       INIT_DELAYED_WORK(&dev->ts_worker, tsc210x_pressure);
+       INIT_DELAYED_WORK(&dev->sensor_worker, tsc210x_input_scan);
+
+       /* Setup the communication bus */
+       dev_set_drvdata(&spi->dev, dev);
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       err = spi_setup(spi);
+       if (err)
+               goto err_spi;
+
+       /* Now try to detect the chip, make first contact.  These chips
+        * don't self-identify, but we can expect that the status register
+        * reports the ADC is idle and use that as a sanity check.  (It'd
+        * be even better if we did a soft reset first...)
+        */
+       reg = tsc210x_read_sync(dev, TSC210X_TS_ADC_CTRL);
+       if (reg < 0) {
+               err = reg;
+               dev_dbg(&dev->spi->dev, "adc_ctrl, err %d\n", err);
+               goto err_spi;
+       }
+       if (!(reg & (1 << 14))) {
+               err = -EIO;
+               dev_dbg(&dev->spi->dev, "adc_ctrl, busy? - %04x\n", reg);
+               goto err_spi;
+       }
+
+       reg = tsc210x_read_sync(dev, TSC210X_AUDIO3_CTRL);
+       if (reg < 0) {
+               err = reg;
+               dev_dbg(&dev->spi->dev, "revision, err %d\n", err);
+               goto err_spi;
+       }
+       if (reg == 0xffff) {
+               err = -ENODEV;
+               dev_dbg(&dev->spi->dev, "no device, err %d\n", err);
+               goto err_spi;
+       }
+       dev_info(&spi->dev, "rev %d, irq %d\n", reg & 0x0007, spi->irq);
+
+       err = tsc210x_configure(dev);
+       if (err)
+               goto err_spi;
+
+       /* We want no interrupts before configuration succeeds.  */
+       mutex_lock(&dev->queue_lock);
+       dev->flushing = 1;
+
+       if (request_irq(spi->irq, tsc210x_handler, IRQF_SAMPLE_RANDOM |
+                               IRQF_TRIGGER_FALLING, spi->dev.driver->name,
+                               dev)) {
+               dev_dbg(&spi->dev, "Could not allocate touchscreen IRQ!\n");
+               err = -EINVAL;
+               goto err_irq;
+       }
+
+       /* Register subdevices controlled by the TSC 2101/2102 */
+       tsc210x_ts_device.dev.platform_data = dev;
+       tsc210x_ts_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc210x_ts_device);
+       if (err)
+               goto err_irq;
+
+       tsc210x_hwmon_device.dev.platform_data = pdata;
+       tsc210x_hwmon_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc210x_hwmon_device);
+       if (err)
+               goto err_hwmon;
+
+       tsc210x_alsa_device.dev.platform_data = pdata->alsa_config;
+       tsc210x_alsa_device.dev.parent = &spi->dev;
+       err = platform_device_register(&tsc210x_alsa_device);
+       if (err)
+               goto err_alsa;
+
+       dev->flushing = 0;
+       mutex_unlock(&dev->queue_lock);
+       return 0;
+
+err_alsa:
+       platform_device_unregister(&tsc210x_hwmon_device);
+err_hwmon:
+       platform_device_unregister(&tsc210x_ts_device);
+err_irq:
+       mutex_unlock(&dev->queue_lock);
+err_spi:
+       dev_set_drvdata(&spi->dev, NULL);
+       clk_disable(dev->bclk_ck);
+       clk_put(dev->bclk_ck);
+err_clk:
+       kfree(dev->transfers);
+err_buffers:
+       destroy_workqueue(dev->queue);
+err_queue:
+       kfree(dev);
+       return err;
+}
+
+static int tsc2101_probe(struct spi_device *spi)
+{
+       return tsc210x_probe(spi, tsc2101);
+}
+
+static int tsc2102_probe(struct spi_device *spi)
+{
+       return tsc210x_probe(spi, tsc2102);
+}
+
+static int tsc210x_remove(struct spi_device *spi)
+{
+       struct tsc210x_dev *dev = dev_get_drvdata(&spi->dev);
+
+       /* Stop the inputs scan loop */
+       mutex_lock(&dev->queue_lock);
+       dev->flushing = 1;
+       cancel_delayed_work(&dev->sensor_worker);
+       mutex_unlock(&dev->queue_lock);
+       flush_workqueue(dev->queue);
+
+       /* Wait for pen-up */
+       while (dev->pendown)
+               flush_workqueue(dev->queue);
+
+       /* Abort current conversion and power down the ADC */
+       tsc210x_write_sync(dev, TSC210X_TS_ADC_CTRL, TSC210X_ADC_ADST);
+       /* NOTE: write_sync() could fail */
+
+       destroy_workqueue(dev->queue);
+
+       platform_device_unregister(&tsc210x_ts_device);
+       platform_device_unregister(&tsc210x_hwmon_device);
+       platform_device_unregister(&tsc210x_alsa_device);
+
+       dev_set_drvdata(&spi->dev, NULL);
+
+       /* Release the BCLK */
+       clk_disable(dev->bclk_ck);
+       clk_put(dev->bclk_ck);
+
+       kfree(dev->transfers);
+       kfree(dev);
+
+       return 0;
+}
+
+static struct spi_driver tsc2101_driver = {
+       .probe          = tsc2101_probe,
+       .remove         = tsc210x_remove,
+       .suspend        = tsc210x_suspend,
+       .resume         = tsc210x_resume,
+       .driver         = {
+               .name   = "tsc2101",
+               .owner  = THIS_MODULE,
+               .bus    = &spi_bus_type,
+       },
+};
+
+static struct spi_driver tsc2102_driver = {
+       .probe          = tsc2102_probe,
+       .remove         = tsc210x_remove,
+       .suspend        = tsc210x_suspend,
+       .resume         = tsc210x_resume,
+       .driver         = {
+               .name   = "tsc2102",
+               .owner  = THIS_MODULE,
+               .bus    = &spi_bus_type,
+       },
+};
+
+static char __initdata banner[] = KERN_INFO "TI TSC210x driver initializing\n";
+
+static int __init tsc210x_init(void)
+{
+       int err;
+       printk(banner);
+
+       settings.ts_msecs = 20;
+       settings.mode_msecs = 1000;
+
+       err = spi_register_driver(&tsc2101_driver);
+       if (err != 0)
+               return err;
+
+       err = spi_register_driver(&tsc2102_driver);
+       if (err != 0)
+               spi_unregister_driver(&tsc2101_driver);
+
+       return err;
+}
+module_init(tsc210x_init);
+
+static void __exit tsc210x_exit(void)
+{
+       spi_unregister_driver(&tsc2101_driver);
+       spi_unregister_driver(&tsc2102_driver);
+}
+module_exit(tsc210x_exit);
+
+MODULE_AUTHOR("Andrzej Zaborowski");
+MODULE_DESCRIPTION("Interface driver for TI TSC210x chips.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc2301-core.c b/drivers/spi/tsc2301-core.c
new file mode 100644 (file)
index 0000000..939bc48
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * TSC2301 driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+
+#ifdef CONFIG_ARCH_OMAP
+#include <mach/gpio.h>
+#endif
+
+u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg)
+{
+       struct spi_transfer t[2];
+       struct spi_message m;
+       u16 data = 0, cmd;
+
+       cmd = reg;
+       cmd |= 0x8000;
+
+       memset(t, 0, sizeof(t));
+       spi_message_init(&m);
+       m.spi = tsc->spi;
+
+       t[0].tx_buf = &cmd;
+       t[0].rx_buf = NULL;
+       t[0].len = 2;
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].tx_buf = NULL;
+       t[1].rx_buf = &data;
+       t[1].len = 2;
+       spi_message_add_tail(&t[1], &m);
+
+       spi_sync(m.spi, &m);
+
+       return data;
+}
+
+void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u16 data[2];
+
+       /* Now we prepare the command for transferring */
+       data[0] = reg;
+       data[1] = val;
+
+       spi_message_init(&m);
+       m.spi = tsc->spi;
+
+       memset(&t, 0, sizeof(t));
+       t.tx_buf = data;
+       t.rx_buf = NULL;
+       t.len = 4;
+       spi_message_add_tail(&t, &m);
+
+       spi_sync(m.spi, &m);
+}
+
+void tsc2301_write_kbc(struct tsc2301 *tsc, int val)
+{
+       u16 w;
+
+       w = tsc->config2_shadow;
+       w &= ~(0x03 << 14);
+       w |= (val & 0x03) << 14;
+       tsc2301_write_reg(tsc, TSC2301_REG_CONFIG2, w);
+       tsc->config2_shadow = w;
+}
+
+void tsc2301_write_pll(struct tsc2301 *tsc,
+                      int pll_n, int pll_a, int pll_pdc, int pct_e, int pll_o)
+{
+       u16 w;
+
+       w = tsc->config2_shadow;
+       w &= ~0x3fff;
+       w |= (pll_n & 0x0f) | ((pll_a & 0x0f) << 4) | ((pll_pdc & 0x0f) << 8);
+       w |= pct_e ? (1 << 12) : 0;
+       w |= pll_o ? (1 << 13) : 0;
+       tsc2301_write_reg(tsc, TSC2301_REG_CONFIG2, w);
+       tsc->config2_shadow = w;
+}
+
+void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *rx_buf, int len)
+{
+       struct spi_transfer t[2];
+       struct spi_message m;
+       u16 cmd, i;
+
+       cmd = reg;
+       cmd |= 0x8000;
+
+       spi_message_init(&m);
+       m.spi = tsc->spi;
+
+       memset(t, 0, sizeof(t));
+       t[0].tx_buf = &cmd;
+       t[0].rx_buf = NULL;
+       t[0].len = 2;
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].tx_buf = NULL;
+       t[1].rx_buf = rx_buf;
+       t[1].len = 2 * len;
+       spi_message_add_tail(&t[1], &m);
+
+       spi_sync(m.spi, &m);
+
+       for (i = 0; i < len; i++)
+               printk(KERN_DEBUG "rx_buf[%d]: %04x\n", i, rx_buf[i]);
+}
+
+static int __devinit tsc2301_probe(struct spi_device *spi)
+{
+       struct tsc2301                  *tsc;
+       struct tsc2301_platform_data    *pdata = spi->dev.platform_data;
+       int r;
+       u16 w;
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
+       if (tsc == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(&spi->dev, tsc);
+       tsc->spi = spi;
+
+       tsc->enable_clock = pdata->enable_clock;
+       tsc->disable_clock = pdata->disable_clock;
+
+       if (pdata->reset_gpio >= 0) {
+               tsc->reset_gpio = pdata->reset_gpio;
+#ifdef CONFIG_ARCH_OMAP
+               r = omap_request_gpio(tsc->reset_gpio);
+               if (r < 0)
+                       goto err1;
+               omap_set_gpio_dataout(tsc->reset_gpio, 1);
+               omap_set_gpio_direction(tsc->reset_gpio, 0);
+               mdelay(1);
+               omap_set_gpio_dataout(tsc->reset_gpio, 0);
+#endif
+       } else
+               tsc->reset_gpio = -1;
+
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       /* The max speed might've been defined by the board-specific
+        * struct */
+       if (!spi->max_speed_hz)
+               spi->max_speed_hz = TSC2301_HZ;
+       spi_setup(spi);
+
+       /* Soft reset */
+       tsc2301_write_reg(tsc, TSC2301_REG_RESET, 0xbb00);
+       msleep(1);
+
+       w = tsc2301_read_reg(tsc, TSC2301_REG_ADC);
+       if (!(w & (1 << 14))) {
+               dev_err(&spi->dev, "invalid ADC reg value: %04x\n", w);
+               r = -ENODEV;
+               goto err1;
+       }
+
+       w = tsc2301_read_reg(tsc, TSC2301_REG_DAC);
+       if (!(w & (1 << 15))) {
+               dev_err(&spi->dev, "invalid DAC reg value: %04x\n", w);
+               r = -ENODEV;
+               goto err1;
+       }
+
+       /* Stop keypad scanning */
+       tsc2301_write_reg(tsc, TSC2301_REG_KEY, 0x4000);
+
+       /* We have to cache this for read-modify-write, since we can't
+        * read back BIT15 */
+       w = tsc2301_read_reg(tsc, TSC2301_REG_CONFIG2);
+       /* By default BIT15 is set */
+       w |= 1 << 15;
+       tsc->config2_shadow = w;
+
+       r = tsc2301_kp_init(tsc, pdata);
+       if (r)
+               goto err1;
+       r = tsc2301_ts_init(tsc, pdata);
+       if (r)
+               goto err2;
+       r = tsc2301_mixer_init(tsc, pdata);
+       if (r)
+               goto err3;
+       return 0;
+
+err3:
+       tsc2301_ts_exit(tsc);
+err2:
+       tsc2301_kp_exit(tsc);
+err1:
+       kfree(tsc);
+       return r;
+}
+
+static int __devexit tsc2301_remove(struct spi_device *spi)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+
+       tsc2301_mixer_exit(tsc);
+        tsc2301_ts_exit(tsc);
+        tsc2301_kp_exit(tsc);
+       kfree(tsc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int tsc2301_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+       int r;
+
+       if ((r = tsc2301_mixer_suspend(tsc)) < 0)
+               return r;
+       if ((r = tsc2301_kp_suspend(tsc)) < 0)
+               goto err1;
+       if ((r = tsc2301_ts_suspend(tsc)) < 0)
+               goto err2;
+
+       return 0;
+err2:
+       tsc2301_kp_resume(tsc);
+err1:
+       tsc2301_mixer_resume(tsc);
+       return r;
+}
+
+static int tsc2301_resume(struct spi_device *spi)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(&spi->dev);
+
+       tsc2301_ts_resume(tsc);
+       tsc2301_kp_resume(tsc);
+       tsc2301_mixer_resume(tsc);
+       return 0;
+}
+#endif
+
+static struct spi_driver tsc2301_driver = {
+       .driver = {
+                  .name = "tsc2301",
+                  .bus = &spi_bus_type,
+                  .owner = THIS_MODULE,
+       },
+#ifdef CONFIG_PM
+       .suspend = tsc2301_suspend,
+       .resume = tsc2301_resume,
+#endif
+       .probe = tsc2301_probe,
+       .remove = __devexit_p(tsc2301_remove),
+};
+
+static int __init tsc2301_init(void)
+{
+       printk("TSC2301 driver initializing\n");
+
+       return spi_register_driver(&tsc2301_driver);
+}
+module_init(tsc2301_init);
+
+static void __exit tsc2301_exit(void)
+{
+       spi_unregister_driver(&tsc2301_driver);
+}
+module_exit(tsc2301_exit);
+
+MODULE_AUTHOR("Juha Yrjölä <juha.yrjola@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/tsc2301-mixer.c b/drivers/spi/tsc2301-mixer.c
new file mode 100644 (file)
index 0000000..31ec87c
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * ALSA Mixer implementation for TSC2301
+ *
+ * Copyright (C) 2006 Nokia Corporation.
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ *          Juha Yrjola
+ *
+ * Some notes about TSC2301:
+ * - PLL will stop when DAC and ADC's are powered down.
+ * - Touchscreen will stop working when audio part is powered up and if audio
+ *   MCLK is stopped. Problem is avoided if audio is powered down before
+ *   stopping MCLK.
+ * - Audio DAC or audio outputs will activate only after 100 msec from the
+ *   chip power-up. Reason seems to be VCM since there is no this delay if the
+ *   chip and VCM (bit AVPD on PD/MISC) were not powered down. The chip will
+ *   consume about 1 mA if all other audio blocks are powered down except the
+ *   chip itself and VCM. Full power down consumes only about few uA.
+ * - Power-down transition could happen earliest about 100 msec after the chip
+ *   power-up. Otherwise power-down will fail if there is no that 100 msec
+ *   on time before it. It's not obvious why is that since chip reports
+ *   power-up to be completed and also PLL output on GPIO_0 is active in few
+ *   milliseconds.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/tsc2301.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+/* shadow register indexes */
+enum {
+       /* audio control and volume registers */
+       AUDCNTL_INDEX,
+       ADCVOL_INDEX,
+       DACVOL_INDEX,
+       BPVOL_INDEX,
+       /* keyclick control register (not needed here) */
+       /* audio power control register */
+       PD_MISC_INDEX,
+       /* TSC2301 GPIO control register */
+       GPIO_INDEX,
+
+       SHADOW_REG_COUNT,
+};
+
+/* structure for driver private data */
+struct tsc2301_mixer {
+       struct tsc2301 *tsc;
+       struct mutex mutex;
+
+       /* shadow registers holding TSC2301 audio registers. Used to hold
+        * their states during the sleep and also to reduce communication with
+        * the chip since get callback functions could get register values
+        * directly from these shadow registers without needing to read them
+        * from the chip */
+       u16 shadow_regs[SHADOW_REG_COUNT];
+
+       /* audio controller driver usage of the ADC and DAC */
+       unsigned adc_enabled:1, dac_enabled:1;
+       unsigned pll_output:1;
+       unsigned mclk_enabled;
+
+       /* latest audio power-up timestamp */
+       unsigned long pu_jiffies;
+
+       /* these are used when upper layer(s) are going to power-down TSC2301
+        * before 100 msec is passed from power-up */
+       struct delayed_work delayed_power_down;
+       unsigned delayed_pd_active:1;
+
+       int (* platform_init)(struct device *);
+       void (* platform_cleanup)(struct device *);
+
+       struct tsc2301_mixer_gpio *mixer_gpios;
+       int n_mixer_gpios;
+};
+
+#define TSC2301_DAC_DELAY              msecs_to_jiffies(100)
+#define TSC2301_MIN_PU_PERIOD          msecs_to_jiffies(100)
+
+#define TSC2301_REG_TO_PVAL(reg)       \
+       (TSC2301_REG_TO_PAGE(reg) << 6 | TSC2301_REG_TO_ADDR(reg))
+#define  TSC2301_PVAL_TO_REG(v)                \
+       (TSC2301_REG((((v) >> 6) & 3),((v) & 0x1f)))
+
+#define TSC2301_VOLUME_MASK            0x7f
+#define TSC2301_MIN_ADCVOL             6
+#define TSC2301_MIN_DACVOL             0
+#define TSC2301_MIN_BPVOL              31
+#define TSC2301_MUTE_LEFT_SHIFT                15
+#define TSC2301_VOL_LEFT_SHIFT         8
+#define TSC2301_MUTE_RIGHT_SHIFT       7
+#define TSC2301_VOL_RIGHT_SHIFT                0
+
+#define TSC2301_INM_MASK               3
+#define TSC2301_INML_SHIFT             12
+#define TSC2301_INMR_SHIFT             10
+
+#define TSC2301_MICG_MASK              3
+#define TSC2301_MICG_MIN               1 /* values 0 & 1 both mean 0 dB */
+#define TSC2301_MICG_SHIFT             8
+
+#define TSC2301_REG_AUDCNTL_MCLK(v)    (((v) & 3) << 6)
+#define TSC2301_REG_AUDCNTL_I2SFS(v)   (((v) & 0xf) << 2)
+#define TSC2301_REG_AUDCNTL_I2SFM(v)   (((v) & 3) << 0)
+
+#define TSC2301_SINGLE(xname, xindex, reg, shadow_index, shift, mask, min) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_tsc2301_info_single, \
+       .get = snd_tsc2301_get_single, \
+       .put = snd_tsc2301_put_single, \
+       .private_value = TSC2301_REG_TO_PVAL(reg) | \
+               (shadow_index << 8) | (shift << 16) | (mask << 24) | \
+               (min << 28) \
+}
+#define TSC2301_SINGLE_MINVAL(v)       (((v) >> 28) & 15)
+#define TSC2301_SINGLE_SHIFT(v)                (((v) >> 16) & 15)
+#define TSC2301_SINGLE_MASK(v)         (((v) >> 24) & 15)
+
+#define TSC2301_DOUBLE(xname, xindex, reg, shadow_index, ls, rs, mask, min) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_tsc2301_info_double, \
+       .get = snd_tsc2301_get_double, \
+       .put = snd_tsc2301_put_double, \
+       .private_value = TSC2301_REG_TO_PVAL(reg) | \
+               (shadow_index << 8) | (min << 11) | \
+               (ls << 16) | (rs << 20) | (mask << 24) \
+}
+#define TSC2301_DOUBLE_MINVAL(v)       (((v) >> 11) & 0x1f)
+#define TSC2301_DOUBLE_LEFT_SHIFT(v)   (((v) >> 16) & 15)
+#define TSC2301_DOUBLE_RIGHT_SHIFT(v)  (((v) >> 20) & 15)
+#define TSC2301_DOUBLE_MASK(v)         (((v) >> 24) & TSC2301_VOLUME_MASK)
+
+#define TSC2301_MUX(xname, xindex, reg, shadow_index, ls, rs, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_tsc2301_info_mux, \
+       .get = snd_tsc2301_get_mux, \
+       .put = snd_tsc2301_put_mux, \
+       .private_value = TSC2301_REG_TO_PVAL(reg) | \
+               (shadow_index << 8) | (ls << 16) | (rs << 20) | (mask << 24) \
+}
+#define TSC2301_MUX_LEFT_SHIFT(v)      (((v) >> 16) & 15)
+#define TSC2301_MUX_RIGHT_SHIFT(v)     (((v) >> 20) & 15)
+#define TSC2301_MUX_MASK(v)            (((v) >> 24) & TSC2301_VOLUME_MASK)
+
+#define TSC2301_BOOL(xname, xindex, reg, shadow_index, shift, invert, state) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_tsc2301_info_bool, \
+       .get = snd_tsc2301_get_bool, \
+       .put = snd_tsc2301_put_bool, \
+       .private_value = TSC2301_REG_TO_PVAL(reg) | \
+               (shadow_index << 8) | (shift << 16) | \
+               (invert << 24) | (state << 25) \
+}
+#define TSC2301_BOOL_SHIFT(v)          (((v) >> 16) & 7)
+#define TSC2301_BOOL_INVERT(v)         (((v) >> 24) & 1)
+#define TSC2301_BOOL_STATE(v)          (((v) >> 25) & 1)
+
+#define TSC2301_SHADOW_INDEX(v)                (((v) >> 8) & 7)
+
+/*
+ * Power-down handler for additional GPIO mixer controls. GPIO state of GPIO
+ * controls whose power-down flag is enabled are set to their false/deactivate
+ * state
+ *
+ * Must be called tsc->mixer->mutex locked
+ */
+static void tsc2301_gpio_power_down(struct tsc2301 *tsc)
+{
+       struct tsc2301_mixer *mix = tsc->mixer;
+       u16 temp;
+       int i;
+
+       temp = mix->shadow_regs[GPIO_INDEX];
+       for (i = 0; i < mix->n_mixer_gpios; i++) {
+               const struct tsc2301_mixer_gpio *mg;
+
+               mg = mix->mixer_gpios + i;
+               if (mg->deactivate_on_pd) {
+                       int gpio = mg->gpio;
+
+                       temp &= ~(1 << gpio);
+                       temp |= mg->inverted << gpio;
+               }
+       }
+       tsc2301_write_reg(tsc, TSC2301_REG_GPIO, temp);
+}
+
+/*
+ * Powers down/up audio blocks which are muted or become unused.
+ * shadow_index >= 0, changes power state of single audio block
+ * shadow_index < 0, changes power state of all blocks
+ *
+ * Must be called tsc->mixer->mutex locked
+ */
+#define TSC2301_MUTE_MASK \
+       ((1 << TSC2301_MUTE_LEFT_SHIFT) | (1 << TSC2301_MUTE_RIGHT_SHIFT))
+static void tsc2301_power_ctrl(struct tsc2301 *tsc, int shadow_index,
+                              int poll_pdsts)
+{
+       struct tsc2301_mixer *mix = tsc->mixer;
+       u16 pd_ctrl, pd_ctrl_old, w;
+       unsigned long timeout;
+       int power_up = 0;
+
+       if (mix->delayed_pd_active) {
+               mix->delayed_pd_active = 0;
+               mix->mclk_enabled--;
+               cancel_delayed_work(&mix->delayed_power_down);
+       }
+
+       pd_ctrl = pd_ctrl_old = mix->shadow_regs[PD_MISC_INDEX];
+       /* power control helper based on used space mixer selections. See
+        * actual power control decisions below */
+       if (shadow_index < 0 || shadow_index == ADCVOL_INDEX) {
+               /* ADC left and right power down control */
+               if (mix->shadow_regs[ADCVOL_INDEX] &
+                   (1 << TSC2301_MUTE_LEFT_SHIFT))
+                       /* left ADC muted. Power down the left ADC */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_ADPDL;
+               else
+                       pd_ctrl &= ~TSC2301_REG_PD_MISC_ADPDL;
+               if (mix->shadow_regs[ADCVOL_INDEX] &
+                   (1 << TSC2301_MUTE_LEFT_SHIFT))
+                       /* right ADC muted. Power down the right ADC */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_ADPDR;
+               else
+                       pd_ctrl &= ~TSC2301_REG_PD_MISC_ADPDR;
+       }
+       if (shadow_index < 0 || shadow_index == DACVOL_INDEX) {
+               /* DAC power down control */
+               if ((mix->shadow_regs[DACVOL_INDEX] &
+                    TSC2301_MUTE_MASK) == TSC2301_MUTE_MASK)
+                       /* both DACs muted. Power down the DAC */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_DAPD;
+               else
+                       pd_ctrl &= ~TSC2301_REG_PD_MISC_DAPD;
+       }
+       if (shadow_index < 0 || shadow_index == BPVOL_INDEX) {
+               /* line bypass power down control */
+               if ((mix->shadow_regs[BPVOL_INDEX] &
+                    TSC2301_MUTE_MASK) == TSC2301_MUTE_MASK)
+                       /* both line bypasses muted. Power down the bypass
+                        * path */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_ABPD;
+               else
+                       pd_ctrl &= ~TSC2301_REG_PD_MISC_ABPD;
+       }
+       if (shadow_index < 0 || shadow_index == AUDCNTL_INDEX) {
+               /* mic bias power down control */
+               if ((mix->shadow_regs[AUDCNTL_INDEX] &
+                    (3 << TSC2301_INML_SHIFT)) &&
+                   (mix->shadow_regs[AUDCNTL_INDEX] &
+                    (3 << TSC2301_INMR_SHIFT)))
+                       /* both ADC channels use other than mic input. Power
+                        * down the mic bias output */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_MIBPD;
+               else
+                       pd_ctrl &= ~TSC2301_REG_PD_MISC_MIBPD;
+       }
+
+       /* power control decisions based on codec usage and user space mixer
+        * selections detected above */
+       pd_ctrl &= ~TSC2301_REG_PD_MISC_APD; /* audio not powered down */
+       if (mix->mclk_enabled) {
+               if (!mix->adc_enabled) {
+                       /* ADC not used, power down both ADC's and mic bias
+                        * output independently of user space mixer
+                        * selections */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_ADPDL;
+                       pd_ctrl |= TSC2301_REG_PD_MISC_ADPDR;
+                       pd_ctrl |= TSC2301_REG_PD_MISC_MIBPD;
+               }
+               if (!mix->dac_enabled) {
+                       /* DAC not used, power down DAC independently of user
+                        * space mixer selections */
+                       pd_ctrl |= TSC2301_REG_PD_MISC_DAPD;
+               }
+
+               if (mix->pll_output) {
+                       /* GPIO_0 is configured as PLL output so audio
+                        * controller is expecting clock from TSC2301. Either
+                        * ADC or DAC must be active in order to keep PLL on */
+                       if ((pd_ctrl & TSC2301_REG_PD_MISC_ADPDL) &&
+                           (pd_ctrl & TSC2301_REG_PD_MISC_ADPDR) &&
+                           (pd_ctrl & TSC2301_REG_PD_MISC_DAPD)) {
+                               /* neither ADC or DAC used. Force ADC on in
+                                * order to keep PLL active */
+                               pd_ctrl &= ~(TSC2301_REG_PD_MISC_ADPDL |
+                                            TSC2301_REG_PD_MISC_ADPDR);
+                       }
+               }
+       } else {
+               /* audio input clock is not enabled so power down DAC and ADC
+                * in order to shutdown PLL and to keep touchscreen and keypad
+                * parts working. Touchscreen and keypad use audio clock when
+                * PLL is on and internal clock otherwise */
+               pd_ctrl |= TSC2301_REG_PD_MISC_DAPD |
+                          TSC2301_REG_PD_MISC_ADPDL |
+                          TSC2301_REG_PD_MISC_ADPDR;
+       }
+
+       if ((pd_ctrl & TSC2301_REG_PD_MISC_ADPDL) &&
+           (pd_ctrl & TSC2301_REG_PD_MISC_ADPDR) &&
+           (pd_ctrl & TSC2301_REG_PD_MISC_DAPD) &&
+           (pd_ctrl & TSC2301_REG_PD_MISC_ABPD)) {
+               /* all ADC, DAC and line bypass path unused. Power down the
+                * whole audio part of the TSC2301 */
+               pd_ctrl |= TSC2301_REG_PD_MISC_APD;
+       }
+
+       if (pd_ctrl == pd_ctrl_old)
+               return;
+
+       /* power down control changed. Update into TSC2301 */
+       if ((pd_ctrl ^ pd_ctrl_old) & TSC2301_REG_PD_MISC_APD) {
+               /* whole audio power state changed. Update GPIO states */
+               if (pd_ctrl & TSC2301_REG_PD_MISC_APD) {
+                       /* power down GPIO controls before powering down
+                        * the codec */
+                       tsc2301_gpio_power_down(tsc);
+                       /* we must really ensure that codec has been on no less
+                        * than 100 msec before doing power-down */
+                       timeout = mix->pu_jiffies + TSC2301_MIN_PU_PERIOD -
+                                 jiffies;
+                       if (timeout <= TSC2301_MIN_PU_PERIOD) {
+                               mix->delayed_pd_active = 1;
+                               mix->mclk_enabled++;
+                               schedule_delayed_work(&mix->delayed_power_down,
+                                                     timeout + 1);
+                               return;
+                       }
+               } else
+                       /* restore GPIOs after codec is powered up */
+                       power_up = 1;
+       }
+       mix->shadow_regs[PD_MISC_INDEX] = pd_ctrl;
+       tsc2301_write_reg(tsc, TSC2301_REG_PD_MISC, pd_ctrl);
+       if (power_up)
+               mix->pu_jiffies = jiffies;
+       if (!poll_pdsts) {
+               if (power_up)
+                       tsc2301_write_reg(tsc, TSC2301_REG_GPIO,
+                                         mix->shadow_regs[GPIO_INDEX]);
+               return;
+       }
+
+       /* wait until power-up/-down is completed */
+       timeout = jiffies + msecs_to_jiffies(100);
+       w = 0;
+       do {
+               if (time_after(jiffies, timeout)) {
+                       /* Print a warning only if the I2S clock is not
+                        * present / out of sync. This can happen during
+                        * init time, when that clock will be turned on
+                        * by another driver like in the OMAP EAC with
+                        * external clock case.
+                        */
+                       if (w & TSC2301_REG_PD_MISC_OTSYN) {
+                               dev_warn(&tsc->spi->dev,
+                                  "I2S clock not in sync or off.\n");
+                       } else {
+                               dev_err(&tsc->spi->dev,
+                                  "power-up/-down timed out "
+                                  "(0x%04x, 0x%04x -> 0x%04x)\n",
+                                  w, pd_ctrl_old, pd_ctrl);
+                       }
+                       goto out;
+               }
+               w = tsc2301_read_reg(tsc, TSC2301_REG_PD_MISC);
+       } while (!(w & TSC2301_REG_PD_MISC_PDSTS));
+
+out:
+       if (((pd_ctrl ^ pd_ctrl_old) & TSC2301_REG_PD_MISC_DAPD) &&
+           !(pd_ctrl & TSC2301_REG_PD_MISC_DAPD)) {
+               /* DAC powered up now. Ensure that DAC and audio outputs are
+                * activated. They are up 100 msec after the chip power-up
+                * command */
+               timeout = mix->pu_jiffies + TSC2301_DAC_DELAY - jiffies;
+               if (timeout <= TSC2301_DAC_DELAY)
+                       schedule_timeout_interruptible(timeout);
+               /* FIXME: This is lazy. We restore GPIOs only after activating
+                * the DAC. It would be better to do some kind of delayed GPIO
+                * restore. That ensures that we restore them also if only ADC
+                * path is activated. But this is required only if there is
+                * some input amplifier, bias control, etc. and their power
+                * state is under TSC GPIO control */
+               tsc2301_write_reg(tsc, TSC2301_REG_GPIO,
+                                 mix->shadow_regs[GPIO_INDEX]);
+       }
+}
+
+static int snd_tsc2301_info_single(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       int mask = TSC2301_SINGLE_MASK(kcontrol->private_value);
+       int minval = TSC2301_SINGLE_MINVAL(kcontrol->private_value);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = minval;
+       uinfo->value.integer.max = mask;
+
+       return 0;
+}
+
+static int snd_tsc2301_get_single(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int mask = TSC2301_SINGLE_MASK(priv);
+       int shift = TSC2301_SINGLE_SHIFT(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg;
+
+       shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+
+       ucontrol->value.integer.value[0] = (shadow_reg >> shift) & mask;
+
+       return 0;
+}
+
+static int snd_tsc2301_put_single(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int mask = TSC2301_SINGLE_MASK(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg, shadow_reg_old;
+       int shift = TSC2301_SINGLE_SHIFT(priv);
+       int reg = TSC2301_PVAL_TO_REG(priv);
+       int changed;
+
+       mutex_lock(&tsc->mixer->mutex);
+       shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+       /* zero bits to be modified */
+       shadow_reg &= ~(mask << shift);
+       /* modify with new value */
+       shadow_reg |= ((ucontrol->value.integer.value[0] & mask) << shift);
+
+       changed = (shadow_reg != shadow_reg_old);
+       tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+
+       /* update into TSC2301 if necessary */
+       if (changed)
+               tsc2301_write_reg(tsc, reg, shadow_reg);
+       mutex_unlock(&tsc->mixer->mutex);
+
+       return changed;
+}
+
+static int snd_tsc2301_info_double(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       /* mask == 1 : Switch
+        * mask > 1 : Max volume */
+       int mask = TSC2301_DOUBLE_MASK(kcontrol->private_value);
+       int minval = TSC2301_DOUBLE_MINVAL(kcontrol->private_value);
+
+       uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN :
+               SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = minval;
+       uinfo->value.integer.max = mask;
+
+       return 0;
+}
+
+static int snd_tsc2301_get_double(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       /* mask == 1 : Switch
+        * mask > 1 : Volume */
+       int mask = TSC2301_DOUBLE_MASK(priv);
+       int ls = TSC2301_DOUBLE_LEFT_SHIFT(priv);
+       int rs = TSC2301_DOUBLE_RIGHT_SHIFT(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg;
+
+       shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+
+       /* invert mute bits for the switches */
+       if (mask == 1)
+               shadow_reg = ~shadow_reg;
+
+       ucontrol->value.integer.value[0] = (shadow_reg >> ls) & mask;
+       ucontrol->value.integer.value[1] = (shadow_reg >> rs) & mask;
+
+       return 0;
+}
+
+static int snd_tsc2301_put_double(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       /* mask == 1 : Switch
+        * mask > 1 : Volume */
+       int mask = TSC2301_DOUBLE_MASK(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg, shadow_reg_old;
+       int ls = TSC2301_DOUBLE_LEFT_SHIFT(priv);
+       int rs = TSC2301_DOUBLE_RIGHT_SHIFT(priv);
+       int reg = TSC2301_PVAL_TO_REG(priv);
+       int changed;
+
+       mutex_lock(&tsc->mixer->mutex);
+       shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+       /* zero bits to be modified */
+       shadow_reg &= ~((mask << ls) | (mask << rs));
+       /* modify with new value */
+       if (mask == 1) {
+               /* switch. Invert switch values for the mute bits */
+               shadow_reg |=
+                       ((~ucontrol->value.integer.value[0] & mask) << ls) |
+                       ((~ucontrol->value.integer.value[1] & mask) << rs);
+       } else {
+               /* volume */
+               shadow_reg |=
+                       (ucontrol->value.integer.value[0] << ls) |
+                       (ucontrol->value.integer.value[1] << rs);
+       }
+
+       changed = (shadow_reg != shadow_reg_old);
+       tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+
+       /* update into TSC2301 if necessary */
+       if (changed)
+               tsc2301_write_reg(tsc, reg, shadow_reg);
+
+       if (mask == 1)
+               /* check is need to power down/up audio blocks in case of
+                * muted state change */
+               tsc2301_power_ctrl(tsc, shadow_index, 0);
+       mutex_unlock(&tsc->mixer->mutex);
+
+       return changed;
+}
+
+static int snd_tsc2301_info_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[4] = {"Mic", "Line", "Line swapped", "Line mono"};
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 2;
+       uinfo->value.enumerated.items = 4;
+       if (uinfo->value.enumerated.item > 3)
+               uinfo->value.enumerated.item = 3;
+       strcpy(uinfo->value.enumerated.name,
+              texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int snd_tsc2301_get_mux(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int mask = TSC2301_MUX_MASK(priv);
+       int ls = TSC2301_MUX_LEFT_SHIFT(priv);
+       int rs = TSC2301_MUX_RIGHT_SHIFT(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg;
+
+       shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+       ucontrol->value.enumerated.item[0] = (shadow_reg >> ls) & mask;
+       ucontrol->value.enumerated.item[1] = (shadow_reg >> rs) & mask;
+
+       return 0;
+}
+
+static int snd_tsc2301_put_mux(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int mask = TSC2301_MUX_MASK(priv);
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       u16 shadow_reg, shadow_reg_old;
+       int ls = TSC2301_MUX_LEFT_SHIFT(priv);
+       int rs = TSC2301_MUX_RIGHT_SHIFT(priv);
+       int reg = TSC2301_PVAL_TO_REG(priv);
+       int changed;
+
+       mutex_lock(&tsc->mixer->mutex);
+       shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+       /* zero bits to be modified */
+       shadow_reg &= ~((mask << ls) | (mask << rs));
+       /* modify with new value */
+       shadow_reg |= (ucontrol->value.enumerated.item[0] << ls);
+       shadow_reg |= (ucontrol->value.enumerated.item[1] << rs);
+
+       changed = (shadow_reg != shadow_reg_old);
+
+       /* update into TSC2301 if necessary */
+       if (changed) {
+               tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+               tsc2301_write_reg(tsc, reg, shadow_reg);
+       }
+
+       /* check is need to power up/down audio blocks in case of ADC input
+        * change */
+       tsc2301_power_ctrl(tsc, shadow_index, 0);
+       mutex_unlock(&tsc->mixer->mutex);
+
+       return changed;
+}
+
+static int snd_tsc2301_info_bool(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+static int snd_tsc2301_get_bool(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       int shift = TSC2301_BOOL_SHIFT(priv);
+       int invert = TSC2301_BOOL_INVERT(priv);
+       u16 shadow_reg;
+
+       shadow_reg = tsc->mixer->shadow_regs[shadow_index];
+       ucontrol->value.integer.value[0] =
+               invert ^ ((shadow_reg >> shift) & 1);
+
+       return 0;
+}
+
+static int snd_tsc2301_put_bool(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct tsc2301 *tsc = kcontrol->private_data;
+       unsigned long priv = kcontrol->private_value;
+       int shadow_index = TSC2301_SHADOW_INDEX(priv);
+       int shift = TSC2301_BOOL_SHIFT(priv);
+       int invert = TSC2301_BOOL_INVERT(priv);
+       int reg = TSC2301_PVAL_TO_REG(priv);
+       u16 shadow_reg, shadow_reg_old;
+       int changed;
+
+       mutex_lock(&tsc->mixer->mutex);
+       shadow_reg = shadow_reg_old = tsc->mixer->shadow_regs[shadow_index];
+
+       /* zero bit to be modified */
+       shadow_reg &= ~(1 << shift);
+       /* modify with new value */
+       shadow_reg |=
+               (invert ^ (ucontrol->value.integer.value[0] & 1)) << shift;
+
+       changed = (shadow_reg != shadow_reg_old);
+
+       /* update into TSC2301 if necessary */
+       if (changed) {
+               tsc->mixer->shadow_regs[shadow_index] = shadow_reg;
+               if ((shadow_index == GPIO_INDEX) &&
+                   (tsc->mixer->shadow_regs[PD_MISC_INDEX] &
+                    TSC2301_REG_PD_MISC_APD)) {
+                       /* changing GPIO control and audio is powered down.
+                        * Update GPIO states according to their power-down
+                        * flag */
+                       tsc2301_gpio_power_down(tsc);
+               } else
+                       tsc2301_write_reg(tsc, reg, shadow_reg);
+       }
+       mutex_unlock(&tsc->mixer->mutex);
+
+       return changed;
+}
+
+/* TSC2301 internal mixer controls */
+static struct snd_kcontrol_new snd_tsc2301_controls[] = {
+       /* stereo ADC input switches and volumes */
+       TSC2301_DOUBLE("Capture Switch", 0,
+               TSC2301_REG_ADCVOL, ADCVOL_INDEX,
+               TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+               1, 0),
+       TSC2301_DOUBLE("Capture Volume", 0,
+               TSC2301_REG_ADCVOL, ADCVOL_INDEX,
+               TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+               TSC2301_VOLUME_MASK, TSC2301_MIN_ADCVOL),
+
+       /* stereo DAC output switches and volumes */
+       TSC2301_DOUBLE("PCM Playback Switch", 0,
+               TSC2301_REG_DACVOL, DACVOL_INDEX,
+               TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+               1, 0),
+       TSC2301_DOUBLE("PCM Playback Volume", 0,
+               TSC2301_REG_DACVOL, DACVOL_INDEX,
+               TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+               TSC2301_VOLUME_MASK, TSC2301_MIN_DACVOL),
+
+       /* stereo line input bypass switches and volumes */
+       TSC2301_DOUBLE("Line Playback Switch", 0,
+               TSC2301_REG_BPVOL, BPVOL_INDEX,
+               TSC2301_MUTE_LEFT_SHIFT, TSC2301_MUTE_RIGHT_SHIFT,
+               1, 0),
+       TSC2301_DOUBLE("Line Playback Volume", 0,
+               TSC2301_REG_BPVOL, BPVOL_INDEX,
+               TSC2301_VOL_LEFT_SHIFT, TSC2301_VOL_RIGHT_SHIFT,
+               TSC2301_VOLUME_MASK, TSC2301_MIN_BPVOL),
+
+       /* mono microphone input gain */
+       TSC2301_SINGLE("Mic Boost", 0,
+               TSC2301_REG_AUDCNTL, AUDCNTL_INDEX,
+               TSC2301_MICG_SHIFT,
+               TSC2301_MICG_MASK, TSC2301_MICG_MIN),
+
+       /* ADC input sources. Both channels could be selected separately */
+       TSC2301_MUX("Capture Source", 0,
+               TSC2301_REG_AUDCNTL, AUDCNTL_INDEX,
+               TSC2301_INML_SHIFT, TSC2301_INMR_SHIFT,
+               TSC2301_INM_MASK),
+};
+
+/* must be called tsc->mixer->mutex locked */
+static void tsc2301_flush_shadow_regs(struct tsc2301 *tsc)
+{
+       int i, page, addr;
+       u16 temp;
+
+       page = TSC2301_REG_TO_PAGE(TSC2301_REG_AUDCNTL);
+       addr = TSC2301_REG_TO_ADDR(TSC2301_REG_AUDCNTL);
+
+       for (i = 0; i < 4; i++) {
+               temp = tsc->mixer->shadow_regs[i];
+               tsc2301_write_reg(tsc, TSC2301_REG(page, addr + i), temp);
+       }
+       temp = tsc->mixer->shadow_regs[GPIO_INDEX];
+       tsc2301_write_reg(tsc, TSC2301_REG_GPIO, temp);
+
+       /* Update power state of all audio blocks depending are they
+        * muted or unused. */
+       tsc2301_power_ctrl(tsc, -1, 0);
+}
+
+#ifdef CONFIG_PM
+int tsc2301_mixer_suspend(struct tsc2301 *tsc)
+{
+       /* power down entire audio section inside TSC2301 in case the
+        * chip is still powered during the system sleep. However this driver
+        * doesn't require that chip is powered because registers are restored
+        * in function tsc2301_mixer_resume */
+       mutex_lock(&tsc->mixer->mutex);
+       tsc2301_gpio_power_down(tsc);
+       tsc->mixer->shadow_regs[PD_MISC_INDEX] |= TSC2301_REG_PD_MISC_APD;
+       tsc2301_write_reg(tsc, TSC2301_REG_PD_MISC,
+                         tsc->mixer->shadow_regs[PD_MISC_INDEX]);
+       mutex_unlock(&tsc->mixer->mutex);
+       return 0;
+}
+
+void tsc2301_mixer_resume(struct tsc2301 *tsc)
+{
+       /* power up the TSC2301 audio section and restore registers */
+       mutex_lock(&tsc->mixer->mutex);
+       tsc->mixer->shadow_regs[PD_MISC_INDEX] &= ~TSC2301_REG_PD_MISC_APD;
+       tsc2301_flush_shadow_regs(tsc);
+       mutex_unlock(&tsc->mixer->mutex);
+}
+#endif
+
+void tsc2301_mixer_enable_mclk(struct device *dev)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+       struct tsc2301_mixer *mix = tsc->mixer;
+
+       mutex_lock(&mix->mutex);
+       if (!mix->mclk_enabled++ && tsc->enable_clock != NULL) {
+               tsc->enable_clock(dev);
+       }
+       tsc2301_power_ctrl(tsc, -1, 1);
+       mutex_unlock(&mix->mutex);
+}
+
+void tsc2301_mixer_disable_mclk(struct device *dev)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+       struct tsc2301_mixer *mix = tsc->mixer;
+
+       mutex_lock(&mix->mutex);
+       mix->mclk_enabled--;
+       tsc2301_power_ctrl(tsc, -1, 1);
+       if (!mix->mclk_enabled && tsc->disable_clock != NULL) {
+               tsc->disable_clock(dev);
+       }
+       mutex_unlock(&mix->mutex);
+}
+
+static void tsc2301_mixer_delayed_power_down(struct work_struct *work)
+{
+       struct tsc2301_mixer *mix = container_of(work, struct tsc2301_mixer,
+                                                delayed_power_down.work);
+       struct tsc2301 *tsc = mix->tsc;
+
+       mutex_lock(&mix->mutex);
+       if (!mix->delayed_pd_active) {
+               mutex_unlock(&mix->mutex);
+               return;
+       }
+       mix->delayed_pd_active = 0;
+       mutex_unlock(&mix->mutex);
+       tsc2301_mixer_disable_mclk(&tsc->spi->dev);
+}
+
+/*
+ * Allows audio controller driver to notify its usage of ADC and DAC
+ */
+void tsc2301_mixer_set_power(struct device *dev, int dac, int adc)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+
+       mutex_lock(&tsc->mixer->mutex);
+       tsc->mixer->adc_enabled = adc;
+       tsc->mixer->dac_enabled = dac;
+
+       /* update power state of all audio blocks */
+       tsc2301_power_ctrl(tsc, -1, 1);
+       mutex_unlock(&tsc->mixer->mutex);
+}
+
+/*
+ * Registers TSC2301 ALSA Mixer controls for the given sound card
+ */
+int tsc2301_mixer_register_controls(struct device *dev, struct snd_card *card)
+{
+       struct tsc2301 *tsc = dev_get_drvdata(dev);
+       struct tsc2301_mixer *mix = tsc->mixer;
+       int i, err;
+
+       /* Register ALSA mixer controls */
+       for (i = 0; i < ARRAY_SIZE(snd_tsc2301_controls); i++) {
+               err = snd_ctl_add(card,
+                                 snd_ctl_new1(&snd_tsc2301_controls[i], tsc));
+               if (err < 0)
+                       return err;
+       }
+
+       if (!mix->n_mixer_gpios)
+               return 0;
+
+       /* Register additional GPIO controls if defined */
+       for (i = 0; i < mix->n_mixer_gpios; i++) {
+               const struct tsc2301_mixer_gpio *mg = mix->mixer_gpios + i;
+               struct snd_kcontrol *ctrlp;
+               struct snd_kcontrol_new ctrl =
+                       TSC2301_BOOL((char *)mg->name, 0,
+                                    TSC2301_REG_GPIO, GPIO_INDEX,
+                                    mg->gpio, mg->inverted, mg->def_enable);
+
+               ctrlp = snd_ctl_new1(&ctrl, tsc);
+               err = snd_ctl_add(card, ctrlp);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+int tsc2301_mixer_init(struct tsc2301 *tsc,
+                      struct tsc2301_platform_data *pdata)
+{
+       struct tsc2301_mixer *mix;
+       int err = 0;
+       u16 w;
+
+       mix = kzalloc(sizeof(*mix), GFP_KERNEL);
+       if (mix == NULL)
+               return -ENOMEM;
+       tsc->mixer = mix;
+
+       mix->tsc = tsc;
+       mutex_init(&mix->mutex);
+       mix->platform_init = pdata->codec_init;
+       mix->platform_cleanup = pdata->codec_cleanup;
+       mix->pll_output = pdata->pll_output;
+
+       INIT_DELAYED_WORK(&mix->delayed_power_down,
+                         tsc2301_mixer_delayed_power_down);
+
+       /* initialize shadow register default values */
+       w = 0xc000;
+       w |= (pdata->mclk_ratio << 6) | (pdata->i2s_sample_rate << 2);
+       w |= pdata->i2s_format;
+       mix->shadow_regs[AUDCNTL_INDEX] = w;
+       mix->shadow_regs[ADCVOL_INDEX] = 0xd7d7;
+       mix->shadow_regs[DACVOL_INDEX] = 0xffff;
+       mix->shadow_regs[BPVOL_INDEX] = 0xe7e7;
+       mix->shadow_regs[PD_MISC_INDEX] = pdata->power_down_blocks;
+
+       /* if extra mixer controls configured, then configure associated
+        * GPIOs as output and drive their default state */
+       if (pdata->n_mixer_gpios) {
+               int i;
+
+               w = 0;
+               for (i = 0; i < pdata->n_mixer_gpios; i++) {
+                       const struct tsc2301_mixer_gpio *mg;
+                       int gpio;
+
+                       mg = pdata->mixer_gpios + i;
+                       gpio = mg->gpio;
+                       w |= (1 << gpio) << 8;
+                       w |= (mg->inverted ^ mg->def_enable) << gpio;
+               }
+               mix->shadow_regs[GPIO_INDEX] = w;
+
+               mix->mixer_gpios = kmalloc(sizeof(*pdata->mixer_gpios) *
+                                          pdata->n_mixer_gpios,
+                                          GFP_KERNEL);
+               if (mix->mixer_gpios == NULL) {
+                       err = -ENOMEM;
+                       goto err1;
+               }
+               memcpy(mix->mixer_gpios, pdata->mixer_gpios,
+                      sizeof(*pdata->mixer_gpios) * pdata->n_mixer_gpios);
+               mix->n_mixer_gpios = pdata->n_mixer_gpios;
+       }
+
+       /* PLL control */
+       tsc2301_write_pll(tsc, pdata->pll_n, pdata->pll_a, pdata->pll_pdc,
+                         0, mix->pll_output ? 0 : 1);
+
+       tsc2301_flush_shadow_regs(tsc);
+
+       if (mix->platform_init != NULL) {
+               err = mix->platform_init(&tsc->spi->dev);
+               if (err < 0)
+                       goto err2;
+       }
+
+       return 0;
+err2:
+       if (mix->mixer_gpios != NULL)
+               kfree(mix->mixer_gpios);
+err1:
+       kfree(mix);
+       return err;
+}
+
+void tsc2301_mixer_exit(struct tsc2301 *tsc)
+{
+       struct tsc2301_mixer *mixer = tsc->mixer;
+
+       if (mixer->platform_cleanup != NULL)
+               mixer->platform_cleanup(&tsc->spi->dev);
+
+       if (mixer->mixer_gpios != NULL)
+               kfree(mixer->mixer_gpios);
+}
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_LICENSE("GPL");
index bcefbddeba5099877981a1717cfd22edfd35e159..3265afe4b553e14a2cdfd7a216e0916da8e16723 100644 (file)
@@ -55,6 +55,7 @@ config USB_ARCH_HAS_EHCI
        default y if PPC_83xx
        default y if SOC_AU1200
        default y if ARCH_IXP4XX
+       default y if ARCH_OMAP34XX
        default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
index acc95b2ac6f85ad24c9fc067bdc511a3e50a9589..222edf1fe3438bd36000c5cb744f11c3139c929e 100644 (file)
@@ -297,7 +297,7 @@ config USB_GADGET_MUSB_HDRC
 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 bb54cca4c54381736ead413cec0e3747e4af9b78..34e9e393f929b5b35b7710d5065ab30fbe25595e 100644 (file)
@@ -2313,6 +2313,13 @@ static int proc_otg_show(struct seq_file *s)
 
        tmp = omap_readl(OTG_REV);
        if (cpu_is_omap24xx()) {
+               /*
+                * REVISIT: Not clear how this works on OMAP2.  trans
+                * is ANDed to produce bits 7 and 8, which might make
+                * sense for USB_TRANSCEIVER_CTRL on OMAP1,
+                * but with CONTROL_DEVCONF, these bits have something to
+                * do with the frame adjustment counter and McBSP2.
+                */
                ctrl_name = "control_devconf";
                trans = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
        } else {
index 228797e54f9cc009f4ed293da9ccc7f6626ea97a..9807d1342e4280aa4570ce49089c7efce5272600 100644 (file)
@@ -41,6 +41,25 @@ config USB_EHCI_HCD
 
          To compile this driver as a module, choose M here: the
          module will be called ehci-hcd.
+choice
+       prompt "PHY/TLL mode"
+       depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+       ---help---
+       Choose PHY or TLL mode of operation
+
+config OMAP_EHCI_PHY_MODE
+       bool "PHY mode: ISP1504 on Port1/2 (NEW 3430ES2.0)"
+       depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+       ---help---
+         EHCI PHY mode. Port1 and Port2 are connected to ISP1504 transcievers
+
+config OMAP_EHCI_TLL_MODE
+       bool "TLL mode: (EXPERIMENTAL)"
+       depends on USB_EHCI_HCD && EXPERIMENTAL && ARCH_OMAP34XX
+       ---help---
+       OMAP EHCI controller has TLL mode of operation for all 3 ports.
+       Use this mode when no transciever is present
+endchoice
 
 config USB_EHCI_ROOT_HUB_TT
        bool "Root Hub Transaction Translators"
index 8409e0705d6365c34e6db7252cc39eb60575877a..068946214f8d907810f986c40338f542b3def2f3 100644 (file)
@@ -1015,6 +1015,11 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
 #endif
 
+#ifdef CONFIG_ARCH_OMAP34XX
+#include "ehci-omap.c"
+#define        PLATFORM_DRIVER         ehci_hcd_omap_driver
+#endif
+
 #ifdef CONFIG_PPC_PS3
 #include "ehci-ps3.c"
 #define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_driver
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
new file mode 100644 (file)
index 0000000..fff4195
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * ehci-omap.c - driver for USBHOST on OMAP 34xx processor
+ *
+ * Bus Glue for OMAP34xx USBHOST 3 port EHCI controller
+ * Tested on OMAP3430 ES2.0 SDP
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ *     Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <mach/gpio.h>
+
+#include "ehci-omap.h"
+
+
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+/* EHCI connected to External PHY */
+
+/* External USB connectivity board: 750-2083-001
+ * Connected to OMAP3430 SDP
+ * The board has Port1 and Port2 connected to ISP1504 in 12-pin ULPI mode
+ */
+
+/* ISSUE1:
+ *      ISP1504 for input clocking mode needs special reset handling
+ *     Hold the PHY in reset by asserting RESET_N signal
+ *     Then start the 60Mhz clock input to PHY
+ *     Release the reset after a delay -
+ *             to get the PHY state machine in working state
+ */
+#define EXTERNAL_PHY_RESET
+#define        EXT_PHY_RESET_GPIO_PORT1        (57)
+#define        EXT_PHY_RESET_GPIO_PORT2        (61)
+#define        EXT_PHY_RESET_DELAY             (10)
+
+/* ISSUE2:
+ * USBHOST supports External charge pump PHYs only
+ * Use the VBUS from Port1 to power VBUS of Port2 externally
+ * So use Port2 as the working ULPI port
+ */
+#define VBUS_INTERNAL_CHARGEPUMP_HACK
+
+#endif /* CONFIG_OMAP_EHCI_PHY_MODE */
+
+/*-------------------------------------------------------------------------*/
+
+/* Define USBHOST clocks for clock management */
+struct ehci_omap_clock_defs {
+       struct clk      *usbhost_ick_clk;
+       struct clk      *usbhost2_120m_fck_clk;
+       struct clk      *usbhost1_48m_fck_clk;
+       struct clk      *usbtll_fck_clk;
+       struct clk      *usbtll_ick_clk;
+};
+
+/* Clock names as per clock framework: May change so keep as #defs */
+#define USBHOST_ICKL           "usbhost_ick"
+#define USBHOST_120M_FCLK      "usbhost_120m_fck"
+#define USBHOST_48M_FCLK       "usbhost_48m_fck"
+#define USBHOST_TLL_ICKL       "usbtll_ick"
+#define USBHOST_TLL_FCLK       "usbtll_fck"
+/*-------------------------------------------------------------------------*/
+
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE
+
+static void omap_usb_utmi_init(struct usb_hcd *hcd, u8 tll_channel_mask)
+{
+       int i;
+
+       /* Use UTMI Ports of TLL */
+       omap_writel((1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT)|
+                       (0<<OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT),
+                                               OMAP_UHH_HOSTCONFIG);
+       /* Enusre bit is set */
+       while (!(omap_readl(OMAP_UHH_HOSTCONFIG) &
+               (1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)));
+
+       dev_dbg(hcd->self.controller, "\nEntered UTMI MODE: success\n");
+
+       /* Program the 3 TLL channels upfront */
+
+       for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+               /* Disable AutoIdle */
+               omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+                           ~(1<<OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT),
+                           OMAP_TLL_CHANNEL_CONF(i));
+               /* Disable BitStuffing */
+               omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+                           ~(1<<OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT),
+                           OMAP_TLL_CHANNEL_CONF(i));
+               /* SDR Mode */
+               omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+                           ~(1<<OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT),
+                           OMAP_TLL_CHANNEL_CONF(i));
+
+       }
+
+       /* Program Common TLL register */
+       omap_writel((1 << OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT) |
+                       (1 << OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT) |
+                       (0 << OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT) |
+                       (0 << OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT),
+                               OMAP_TLL_SHARED_CONF);
+
+       /* Enable channels now */
+       for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+               /* Enable only the channel that is needed */
+               if (!(tll_channel_mask & 1<<i))
+                       continue;
+
+               omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+                           (1<<OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT),
+                           OMAP_TLL_CHANNEL_CONF(i));
+
+               omap_writeb(0xBE, OMAP_TLL_ULPI_SCRATCH_REGISTER(i));
+               dev_dbg(hcd->self.controller, "\nULPI_SCRATCH_REG[ch=%d]"
+                       "= 0x%02x\n",
+                       i+1, omap_readb(OMAP_TLL_ULPI_SCRATCH_REGISTER(i)));
+       }
+}
+
+#else
+# define omap_usb_utmi_init(x, y)      0
+#endif
+
+
+/* omap_start_ehc
+ *     - Start the TI USBHOST controller
+ */
+static int omap_start_ehc(struct platform_device *dev, struct usb_hcd *hcd)
+{
+       struct ehci_omap_clock_defs *ehci_clocks;
+
+       dev_dbg(hcd->self.controller, ": starting TI EHCI USB Controller\n");
+
+       ehci_clocks = (struct ehci_omap_clock_defs *)(
+                               ((char *)hcd_to_ehci(hcd)) +
+                                       sizeof(struct ehci_hcd));
+
+       /* Start DPLL5 Programming:
+        * Clock Framework is not doing this now:
+        * This will be done in clock framework later
+        */
+       /* Enable DPLL 5 : Based on Input of 13Mhz*/
+       cm_write_mod_reg((12 << OMAP3430ES2_PERIPH2_DPLL_DIV_SHIFT)|
+                       (120 << OMAP3430ES2_PERIPH2_DPLL_MULT_SHIFT),
+                       PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
+
+       cm_write_mod_reg(1 << OMAP3430ES2_DIV_120M_SHIFT,
+                       PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
+
+       cm_write_mod_reg((7 << OMAP3430ES2_PERIPH2_DPLL_FREQSEL_SHIFT) |
+                       (7 << OMAP3430ES2_EN_PERIPH2_DPLL_SHIFT),
+                       PLL_MOD, OMAP3430ES2_CM_CLKEN2);
+
+       while (!(cm_read_mod_reg(PLL_MOD, CM_IDLEST2) &
+                               OMAP3430ES2_ST_PERIPH2_CLK_MASK))
+               dev_dbg(hcd->self.controller,
+                       "idlest2 = 0x%x\n",
+                       cm_read_mod_reg(PLL_MOD, CM_IDLEST2));
+       /* End DPLL5 programming */
+
+
+       /* PRCM settings for USBHOST:
+        * Interface clk un-related to domain transition
+        */
+       cm_write_mod_reg(0 << OMAP3430ES2_AUTO_USBHOST_SHIFT,
+                               OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
+
+       /* Disable sleep dependency with MPU and IVA */
+       cm_write_mod_reg((0 << OMAP3430ES2_EN_MPU_SHIFT) |
+                               (0 << OMAP3430ES2_EN_IVA2_SHIFT),
+                               OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
+
+       /* Disable Automatic transition of clock */
+       cm_write_mod_reg(0 << OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT,
+                               OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
+
+       /* Enable Clocks for USBHOST */
+       ehci_clocks->usbhost_ick_clk = clk_get(&dev->dev,
+                                               USBHOST_ICKL);
+       if (IS_ERR(ehci_clocks->usbhost_ick_clk))
+               return PTR_ERR(ehci_clocks->usbhost_ick_clk);
+       clk_enable(ehci_clocks->usbhost_ick_clk);
+
+
+       ehci_clocks->usbhost2_120m_fck_clk = clk_get(&dev->dev,
+                                                       USBHOST_120M_FCLK);
+       if (IS_ERR(ehci_clocks->usbhost2_120m_fck_clk))
+               return PTR_ERR(ehci_clocks->usbhost2_120m_fck_clk);
+       clk_enable(ehci_clocks->usbhost2_120m_fck_clk);
+
+       ehci_clocks->usbhost1_48m_fck_clk = clk_get(&dev->dev,
+                                               USBHOST_48M_FCLK);
+       if (IS_ERR(ehci_clocks->usbhost1_48m_fck_clk))
+               return PTR_ERR(ehci_clocks->usbhost1_48m_fck_clk);
+       clk_enable(ehci_clocks->usbhost1_48m_fck_clk);
+
+
+#ifdef EXTERNAL_PHY_RESET
+       /* Refer: ISSUE1 */
+       omap_request_gpio(EXT_PHY_RESET_GPIO_PORT1);
+       omap_set_gpio_direction(EXT_PHY_RESET_GPIO_PORT1, 0);
+       omap_request_gpio(EXT_PHY_RESET_GPIO_PORT2);
+       omap_set_gpio_direction(EXT_PHY_RESET_GPIO_PORT2, 0);
+       omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT1, 0);
+       omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT2, 0);
+       /* Hold the PHY in RESET for enough time till DIR is high */
+       udelay(EXT_PHY_RESET_DELAY);
+#endif
+
+       /* Configure TLL for 60Mhz clk for ULPI */
+       ehci_clocks->usbtll_fck_clk = clk_get(&dev->dev, USBHOST_TLL_FCLK);
+       if (IS_ERR(ehci_clocks->usbtll_fck_clk))
+               return PTR_ERR(ehci_clocks->usbtll_fck_clk);
+       clk_enable(ehci_clocks->usbtll_fck_clk);
+
+       ehci_clocks->usbtll_ick_clk = clk_get(&dev->dev, USBHOST_TLL_ICKL);
+       if (IS_ERR(ehci_clocks->usbtll_ick_clk))
+               return PTR_ERR(ehci_clocks->usbtll_ick_clk);
+       clk_enable(ehci_clocks->usbtll_ick_clk);
+
+       /* Disable Auto Idle of USBTLL */
+       cm_write_mod_reg((0 << OMAP3430ES2_AUTO_USBTLL_SHIFT),
+                               CORE_MOD, CM_AUTOIDLE3);
+
+       /* Wait for TLL to be Active */
+       while ((cm_read_mod_reg(CORE_MOD, OMAP2430_CM_IDLEST3) &
+               (1 << OMAP3430ES2_ST_USBTLL_SHIFT)));
+
+       /* perform TLL soft reset, and wait until reset is complete */
+       omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+                       OMAP_USBTLL_SYSCONFIG);
+       /* Wait for TLL reset to complete */
+       while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+               (1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+
+       dev_dbg(hcd->self.controller, "\n TLL RESET DONE\n");
+
+       /* (1<<3) = no idle mode only for initial debugging */
+       omap_writel((1 << OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT) |
+                       (1 << OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT) |
+                       (1 << OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT),
+                       OMAP_USBTLL_SYSCONFIG);
+
+
+       /* Put UHH in NoIdle/NoStandby mode */
+       omap_writel((0 << OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT) |
+                       (1 << OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT) |
+                       (1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT) |
+                       (1 << OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT) |
+                       (1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT),
+                       OMAP_UHH_SYSCONFIG);
+
+#ifdef CONFIG_OMAP_EHCI_PHY_MODE
+       /* Bypass the TLL module for PHY mode operation */
+       omap_writel((0 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT)|
+                       (1<<OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT)|
+                       (0<<OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT),
+                                               OMAP_UHH_HOSTCONFIG);
+       /* Ensure that BYPASS is set */
+       while (omap_readl(OMAP_UHH_HOSTCONFIG) &
+               (1 << OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT));
+
+       dev_dbg(hcd->self.controller, "Entered ULPI PHY MODE: success");
+
+#else
+       /* Enable UTMI mode for all 3 TLL channels */
+       omap_usb_utmi_init(hcd,
+               OMAP_TLL_CHANNEL_1_EN_MASK |
+               OMAP_TLL_CHANNEL_2_EN_MASK |
+               OMAP_TLL_CHANNEL_3_EN_MASK
+               );
+#endif
+
+#ifdef EXTERNAL_PHY_RESET
+       /* Refer ISSUE1:
+        * Hold the PHY in RESET for enough time till PHY is settled and ready
+        */
+       udelay(EXT_PHY_RESET_DELAY);
+       omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT1, 1);
+       omap_set_gpio_dataout(EXT_PHY_RESET_GPIO_PORT2, 1);
+#endif
+
+#ifdef VBUS_INTERNAL_CHARGEPUMP_HACK
+       /* Refer ISSUE2: LINK assumes external charge pump */
+
+       /* use Port1 VBUS to charge externally Port2:
+        *      So for PHY mode operation use Port2 only
+        */
+       omap_writel((0xA << EHCI_INSNREG05_ULPI_REGADD_SHIFT) |/* OTG ctrl reg*/
+                       (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) |/*   Write */
+                       (1 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) |/* Port1 */
+                       (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) |/* Start */
+                       (0x26),
+                       EHCI_INSNREG05_ULPI);
+
+       while (!(omap_readl(EHCI_INSNREG05_ULPI) &
+               (1<<EHCI_INSNREG05_ULPI_CONTROL_SHIFT)));
+
+#endif
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void omap_stop_ehc(struct platform_device *dev, struct usb_hcd *hcd)
+{
+       struct ehci_omap_clock_defs *ehci_clocks;
+
+       ehci_clocks = (struct ehci_omap_clock_defs *)
+                       (((char *)hcd_to_ehci(hcd)) + sizeof(struct ehci_hcd));
+
+       dev_dbg(hcd->self.controller, ": stopping TI EHCI USB Controller\n");
+
+       /* Reset OMAP modules for insmod/rmmod to work */
+       omap_writel((1<<1), OMAP_UHH_SYSCONFIG);
+       while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<0)));
+       while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<1)));
+       while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1<<2)));
+       dev_dbg(hcd->self.controller,
+               "UHH RESET DONE OMAP_UHH_SYSSTATUS %x !!\n",
+                       omap_readl(OMAP_UHH_SYSSTATUS));
+
+       omap_writel((1<<1), OMAP_USBTLL_SYSCONFIG);
+       while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) & (1<<0)));
+       dev_dbg(hcd->self.controller, ":TLL RESEET DONE");
+
+       if (ehci_clocks->usbtll_fck_clk != NULL) {
+               clk_disable(ehci_clocks->usbtll_fck_clk);
+               clk_put(ehci_clocks->usbtll_fck_clk);
+               ehci_clocks->usbtll_fck_clk = NULL;
+       }
+
+       if (ehci_clocks->usbhost_ick_clk != NULL) {
+               clk_disable(ehci_clocks->usbhost_ick_clk);
+               clk_put(ehci_clocks->usbhost_ick_clk);
+               ehci_clocks->usbhost_ick_clk = NULL;
+       }
+
+       if (ehci_clocks->usbhost1_48m_fck_clk != NULL) {
+               clk_disable(ehci_clocks->usbhost1_48m_fck_clk);
+               clk_put(ehci_clocks->usbhost1_48m_fck_clk);
+               ehci_clocks->usbhost1_48m_fck_clk = NULL;
+       }
+
+       if (ehci_clocks->usbhost2_120m_fck_clk != NULL) {
+               clk_disable(ehci_clocks->usbhost2_120m_fck_clk);
+               clk_put(ehci_clocks->usbhost2_120m_fck_clk);
+               ehci_clocks->usbhost2_120m_fck_clk = NULL;
+       }
+
+       if (ehci_clocks->usbtll_ick_clk != NULL) {
+               clk_disable(ehci_clocks->usbtll_ick_clk);
+               clk_put(ehci_clocks->usbtll_ick_clk);
+               ehci_clocks->usbtll_ick_clk = NULL;
+       }
+
+
+#ifdef EXTERNAL_PHY_RESET
+       omap_free_gpio(EXT_PHY_RESET_GPIO_PORT1);
+       omap_free_gpio(EXT_PHY_RESET_GPIO_PORT2);
+#endif
+
+       dev_dbg(hcd->self.controller,
+               ": Clock to USB host has been disabled\n");
+}
+
+static const struct hc_driver ehci_omap_hc_driver;
+
+/*-------------------------------------------------------------------------*/
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * ehci_hcd_omap_drv_probe - initialize TI-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+static int ehci_hcd_omap_drv_probe(struct platform_device *dev)
+{
+       int retval = 0;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+
+       dev_dbg(&dev->dev, "ehci_hcd_omap_drv_probe()");
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       if (dev->resource[1].flags != IORESOURCE_IRQ) {
+               dev_dbg(&dev->dev, "resource[1] is not IORESOURCE_IRQ");
+               retval = -ENOMEM;
+       }
+
+       hcd = usb_create_hcd(&ehci_omap_hc_driver, &dev->dev, dev->dev.bus_id);
+       if (!hcd)
+               return -ENOMEM;
+
+       retval = omap_start_ehc(dev, hcd);
+       if (retval)
+               return retval;
+
+       hcd->rsrc_start = 0;
+       hcd->rsrc_len = 0;
+       hcd->rsrc_start = dev->resource[0].start;
+       hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               dev_err(&dev->dev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = hcd->regs;
+
+       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       /* cache this readonly data; minimize chip reads */
+       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+
+       /* SET 1 micro-frame Interrupt interval */
+       writel(readl(&ehci->regs->command) | (1<<16), &ehci->regs->command);
+
+       retval = usb_add_hcd(hcd, dev->resource[1].start,
+                               IRQF_DISABLED | IRQF_SHARED);
+       if (retval == 0)
+               return retval;
+
+       dev_dbg(hcd->self.controller, "ERR: add_hcd");
+       omap_stop_ehc(dev, hcd);
+       iounmap(hcd->regs);
+       usb_put_hcd(hcd);
+
+       return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * ehci_hcd_omap_drv_remove - shutdown processing for EHCI HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+static int ehci_hcd_omap_drv_remove(struct platform_device *dev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+       dev_dbg(&dev->dev, "ehci_hcd_omap_drv_remove()");
+
+       iounmap(hcd->regs);
+       usb_remove_hcd(hcd);
+       usb_put_hcd(hcd);
+       omap_stop_ehc(dev, hcd);
+
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_PM
+static int omap_ehci_bus_suspend(struct usb_hcd *hcd)
+{
+       return ehci_bus_suspend(hcd);
+}
+
+static int omap_ehci_bus_resume(struct usb_hcd *hcd)
+{
+       return ehci_bus_resume(hcd);
+}
+#endif
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ehci_omap_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "OMAP-EHCI Host Controller",
+       .hcd_priv_size = sizeof(struct ehci_hcd)
+                               + sizeof(struct ehci_omap_clock_defs),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = ehci_init,
+       .start = ehci_run,
+       .stop = ehci_stop,
+       .shutdown = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+       .bus_suspend = omap_ehci_bus_suspend,
+       .bus_resume = omap_ehci_bus_resume,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+MODULE_ALIAS("omap-ehci");
+static struct platform_driver ehci_hcd_omap_driver = {
+       .probe = ehci_hcd_omap_drv_probe,
+       .remove = ehci_hcd_omap_drv_remove,
+       .shutdown = usb_hcd_platform_shutdown,
+       /*.suspend      = ehci_hcd_omap_drv_suspend, */
+       /*.resume       = ehci_hcd_omap_drv_resume, */
+       .driver = {
+               .name = "ehci-omap",
+               .bus = &platform_bus_type
+       }
+};
diff --git a/drivers/usb/host/ehci-omap.h b/drivers/usb/host/ehci-omap.h
new file mode 100644 (file)
index 0000000..9e4378f
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * ehci-omap.h - register definitions for USBHOST in OMAP 34xx
+ *
+ * Copyright (C) 2007-2008 Texas Instruments, Inc.
+ *     Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#ifndef __EHCI_OMAP_H
+#define __EHCI_OMAP_H
+
+#include <mach/hardware.h>
+#include "../../../arch/arm/mach-omap2/cm.h"
+#include "../../../arch/arm/mach-omap2/cm-regbits-34xx.h"
+
+/*
+ * OMAP USBHOST Register addresses: PHYSICAL ADDRESSES
+ *     Use omap_readl()/omap_writel() functions
+ */
+
+/* USBHOST: TLL, UUH, OHCI, EHCI */
+#define        OMAP_USBHOST_BASE       (L4_34XX_BASE + 0x60000)
+
+/* TLL Register Set */
+#define        OMAP_USBHOST_TLL_BASE   (OMAP_USBHOST_BASE + 0x2000)
+#define        OMAP_USBTLL_REVISION    (OMAP_USBHOST_TLL_BASE + 0x00)
+#define        OMAP_USBTLL_SYSCONFIG   (OMAP_USBHOST_TLL_BASE + 0x10)
+       #define OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT   8
+       #define OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT   3
+       #define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT   2
+       #define OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT   1
+       #define OMAP_USBTLL_SYSCONFIG_AUTOIDLE_SHIFT    0
+#define        OMAP_USBTLL_SYSSTATUS   (OMAP_USBHOST_TLL_BASE + 0x14)
+       #define OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT   0
+#define        OMAP_USBTLL_IRQSTATUS   (OMAP_USBHOST_TLL_BASE + 0x18)
+#define        OMAP_USBTLL_IRQENABLE   (OMAP_USBHOST_TLL_BASE + 0x1C)
+
+#define        OMAP_TLL_SHARED_CONF    (OMAP_USBHOST_TLL_BASE + 0x30)
+       #define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT        6
+       #define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT      5
+       #define OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT        2
+       #define OMAP_TLL_SHARED_CONF_FCLK_REQ_SHIFT             1
+       #define OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT           0
+
+#define        OMAP_TLL_CHANNEL_CONF(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x040 + 0x004 * num))
+       #define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT      11
+       #define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE_SHIFT   10
+       #define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT        9
+       #define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT         8
+       #define OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT              0
+
+#define        OMAP_TLL_ULPI_FUNCTION_CTRL(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x804 + 0x100 * num))
+#define        OMAP_TLL_ULPI_INTERFACE_CTRL(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x807 + 0x100 * num))
+#define        OMAP_TLL_ULPI_OTG_CTRL(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x80A + 0x100 * num))
+#define        OMAP_TLL_ULPI_INT_EN_RISE(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x80D + 0x100 * num))
+#define        OMAP_TLL_ULPI_INT_EN_FALL(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x810 + 0x100 * num))
+#define        OMAP_TLL_ULPI_INT_STATUS(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x813 + 0x100 * num))
+#define        OMAP_TLL_ULPI_INT_LATCH(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x814 + 0x100 * num))
+#define        OMAP_TLL_ULPI_DEBUG(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x815 + 0x100 * num))
+#define        OMAP_TLL_ULPI_SCRATCH_REGISTER(num)\
+                       (OMAP_USBHOST_TLL_BASE + (0x816 + 0x100 * num))
+
+#define OMAP_TLL_CHANNEL_COUNT         3
+       #define OMAP_TLL_CHANNEL_1_EN_MASK      1
+       #define OMAP_TLL_CHANNEL_2_EN_MASK      2
+       #define OMAP_TLL_CHANNEL_3_EN_MASK      4
+
+/* UHH Register Set */
+#define        OMAP_USBHOST_UHH_BASE   (OMAP_USBHOST_BASE + 0x4000)
+#define        OMAP_UHH_REVISION       (OMAP_USBHOST_UHH_BASE + 0x00)
+#define        OMAP_UHH_SYSCONFIG      (OMAP_USBHOST_UHH_BASE + 0x10)
+       #define OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT      12
+       #define OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT      8
+       #define OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT      3
+       #define OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT      2
+       #define OMAP_UHH_SYSCONFIG_SOFTRESET_SHIFT      1
+       #define OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT       0
+
+#define        OMAP_UHH_SYSSTATUS      (OMAP_USBHOST_UHH_BASE + 0x14)
+#define        OMAP_UHH_HOSTCONFIG     (OMAP_USBHOST_UHH_BASE + 0x40)
+       #define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS_SHIFT   0
+       #define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT        2
+       #define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT        3
+       #define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT       4
+       #define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT        5
+
+#define        OMAP_UHH_DEBUG_CSR      (OMAP_USBHOST_UHH_BASE + 0x44)
+
+/* EHCI Register Set */
+#define        OMAP_USBHOST_EHCI_BASE  (OMAP_USBHOST_BASE + 0x4800)
+#define        EHCI_INSNREG05_ULPI             (OMAP_USBHOST_EHCI_BASE + 0xA4)
+       #define EHCI_INSNREG05_ULPI_CONTROL_SHIFT       31
+       #define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT       24
+       #define EHCI_INSNREG05_ULPI_OPSEL_SHIFT         22
+       #define EHCI_INSNREG05_ULPI_REGADD_SHIFT        16
+       #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT     8
+       #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT        0
+
+/* OHCI Register Set */
+#define        OMAP_USBHOST_OHCI_BASE  (OMAP_USBHOST_BASE + 0x4400)
+
+#endif/* __EHCI_OMAP_H*/
index 95b3ec89c126cdd0609306c034ae348a1324a184..91697bdb399f625eba508a0ea80da21099a1556b 100644 (file)
@@ -231,7 +231,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();
        }
@@ -319,7 +319,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");
@@ -344,7 +344,12 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
                goto err1;
        }
 
-       hcd->regs = (void __iomem *) (int) IO_ADDRESS(hcd->rsrc_start);
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               dev_err(&pdev->dev, "can't ioremap OHCI HCD\n");
+               retval = -ENOMEM;
+               goto err2;
+       }
 
        ohci = hcd_to_ohci(hcd);
        ohci_hcd_init(ohci);
@@ -355,11 +360,11 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                retval = -ENXIO;
-               goto err2;
+               goto err3;
        }
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
        if (retval)
-               goto err2;
+               goto err3;
 
        host_initialized = 1;
 
@@ -367,6 +372,8 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,
                omap_ohci_clock_power(0);
 
        return 0;
+err3:
+       iounmap(hcd->regs);
 err2:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
@@ -401,6 +408,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
        }
        if (machine_is_omap_osk())
                omap_free_gpio(9);
+       iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        clk_put(usb_dc_ck);
index 75baf181a8cdff08098ec180e23cffdaaa430987..217f4978e50b7364f8255826fb7dce72acbf8274 100644 (file)
 #include <linux/clk.h>
 #include <linux/io.h>
 
-#include <asm/arch/hardware.h>
-#include <asm/arch/memory.h>
-#include <asm/arch/gpio.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <asm/memory.h>
 #include <asm/mach-types.h>
 
 #include "musb_core.h"
 
 #ifdef CONFIG_MACH_DAVINCI_EVM
-#include <asm/arch/i2c-client.h>
+#include <mach/i2c-client.h>
 #endif
 
 #include "davinci.h"
index 9d2dcb121c5e95cc7e6ba81a5cdfa59ae07637ae..be4e77923c26e8fe2f2967e037d2ad09652f36e0 100644 (file)
@@ -215,12 +215,14 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
 
 int __init musb_platform_init(struct musb *musb)
 {
+       struct otg_transceiver *x = otg_get_transceiver();
        u32 l;
 
 #if defined(CONFIG_ARCH_OMAP2430)
        omap_cfg_reg(AE5_2430_USB0HS_STP);
 #endif
 
+       musb->xceiv = *x;
        musb_platform_resume(musb);
 
        l = omap_readl(OTG_SYSCONFIG);
index 52f7f29cebdadf02f82ec5d5a910e04f93749377..7e073a0d7ac9b5428797d27857e883cd227d34f9 100644 (file)
@@ -15,8 +15,8 @@
 #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 <mach/dma.h>
+#include <mach/mux.h>
 
 #include "musb_core.h"
 
index 44408850e2ebc2d0047e1bae7d7a82a5d735e135..5ebd59151686722fa026fee908368f8d2c0f292e 100644 (file)
@@ -7,6 +7,65 @@ config FB_OMAP
        help
           Frame buffer driver for OMAP based boards.
 
+choice
+       depends on FB_OMAP && MACH_OVERO
+       prompt "Screen resolution"
+       default FB_OMAP_079M3R
+       help
+         Selected desired screen resolution
+
+config FB_OMAP_031M3R
+       boolean "640 x 480 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_048M3R
+       boolean "800 x 600 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_079M3R
+       boolean "1024 x 768 @ 60 Hz Reduced blanking"
+
+config FB_OMAP_092M9R
+       boolean "1280 x 720 @ 60 Hz Reduced blanking"
+
+endchoice
+
+config FB_OMAP_LCDC_EXTERNAL
+       bool "External LCD controller support"
+       depends on FB_OMAP
+       help
+         Say Y here, if you want to have support for boards with an
+         external LCD controller connected to the SoSSI/RFBI interface.
+
+config FB_OMAP_LCDC_HWA742
+       bool "Epson HWA742 LCD controller support"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here if you want to have support for the external
+         Epson HWA742 LCD controller.
+
+config FB_OMAP_LCDC_BLIZZARD
+       bool "Epson Blizzard LCD controller support"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here if you want to have support for the external
+         Epson Blizzard LCD controller.
+
+config FB_OMAP_MANUAL_UPDATE
+       bool "Default to manual update mode"
+       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+       help
+         Say Y here, if your user-space applications are capable of
+         notifying the frame buffer driver when a change has occured in
+          the frame buffer content and thus a reload of the image data to
+         the external frame buffer is required. If unsure, say N.
+
+config FB_OMAP_LCD_MIPID
+       bool "MIPI DBI-C/DCS compatible LCD support"
+       depends on FB_OMAP && SPI_MASTER && CBUS_TAHVO
+       help
+         Say Y here if you want to have support for LCDs compatible with
+         the Mobile Industry Processor Interface DBI-C/DCS
+         specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
+
 config FB_OMAP_BOOTLOADER_INIT
        bool "Check bootloader initialization"
        depends on FB_OMAP
@@ -36,23 +95,4 @@ config FB_OMAP_DMA_TUNE
           answer yes. Answer no if you have a dedicated video
           memory, or don't use any of the accelerated features.
 
-config FB_OMAP_LCDC_EXTERNAL
-       bool "External LCD controller support"
-       depends on FB_OMAP
-       help
-         Say Y here, if you want to have support for boards with an
-         external LCD controller connected to the SoSSI/RFBI interface.
-
-config FB_OMAP_LCDC_HWA742
-       bool "Epson HWA742 LCD controller support"
-       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
-       help
-         Say Y here if you want to have support for the external
-         Epson HWA742 LCD controller.
 
-config FB_OMAP_LCDC_BLIZZARD
-       bool "Epson Blizzard LCD controller support"
-       depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
-       help
-         Say Y here if you want to have support for the external
-         Epson Blizzard LCD controller.
index 99da8b6d2c3650d6418f832add4d221e50ada887..291c46ee588058a5b7e1bc615b5748466b49c8c7 100644 (file)
@@ -8,6 +8,7 @@ objs-yy := omapfb_main.o
 
 objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
 objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
+objs-y$(CONFIG_ARCH_OMAP3) += dispc.o
 
 objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
 objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
@@ -15,8 +16,10 @@ objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
 objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
 objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
 
+objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
 objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
 objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
+objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o
 objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
 objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
 objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
@@ -25,5 +28,14 @@ objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
 objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
 objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
 
+objs-y$(CONFIG_MACH_OMAP_APOLLON) += lcd_apollon.o
+objs-y$(CONFIG_MACH_OMAP_2430SDP) += lcd_2430sdp.o
+objs-y$(CONFIG_MACH_OMAP_3430SDP) += lcd_2430sdp.o
+objs-y$(CONFIG_MACH_OMAP2EVM) += lcd_omap2evm.o
+objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
+objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
+objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
+objs-y$(CONFIG_MACH_OVERO) += lcd_overo.o
+
 omapfb-objs := $(objs-yy)
 
index 9dfcf39d3367370c0d3ec2507aa3bb3e036edef6..6031b89573b236791e2fbbff80c8753429c6bdf4 100644 (file)
@@ -44,6 +44,7 @@
 #define BLIZZARD_CLK_SRC                       0x0e
 #define BLIZZARD_MEM_BANK0_ACTIVATE            0x10
 #define BLIZZARD_MEM_BANK0_STATUS              0x14
+#define BLIZZARD_PANEL_CONFIGURATION           0x28
 #define BLIZZARD_HDISP                         0x2a
 #define BLIZZARD_HNDP                          0x2c
 #define BLIZZARD_VDISP0                                0x2e
@@ -908,6 +909,35 @@ static int blizzard_set_scale(int plane, int orig_w, int orig_h,
        return 0;
 }
 
+static int blizzard_set_rotate(int angle)
+{
+       u32 l;
+
+       l = blizzard_read_reg(BLIZZARD_PANEL_CONFIGURATION);
+       l &= ~0x03;
+
+       switch (angle) {
+       case 0:
+               l = l | 0x00;
+               break;
+       case 90:
+               l = l | 0x03;
+               break;
+       case 180:
+               l = l | 0x02;
+               break;
+       case 270:
+               l = l | 0x01;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       blizzard_write_reg(BLIZZARD_PANEL_CONFIGURATION, l);
+
+       return 0;
+}
+
 static int blizzard_enable_plane(int plane, int enable)
 {
        if (enable)
@@ -1285,7 +1315,8 @@ static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
        caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
                OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
                OMAPFB_CAPS_WINDOW_SCALE |
-               OMAPFB_CAPS_WINDOW_OVERLAY;
+               OMAPFB_CAPS_WINDOW_OVERLAY |
+               OMAPFB_CAPS_WINDOW_ROTATE;
        if (blizzard.te_connected)
                caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
        caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
@@ -1560,6 +1591,7 @@ struct lcd_ctrl blizzard_ctrl = {
        .setup_plane            = blizzard_setup_plane,
        .set_scale              = blizzard_set_scale,
        .enable_plane           = blizzard_enable_plane,
+       .set_rotate             = blizzard_set_rotate,
        .update_window          = blizzard_update_window_async,
        .sync                   = blizzard_sync,
        .suspend                = blizzard_suspend,
index 6efcf89e7fbe9667e9f4722e91fd8dfeb0964bd3..ce4c4debb7fa1f4e9280c7daec3ac21ab03ead2a 100644 (file)
@@ -156,7 +156,7 @@ struct resmap {
 };
 
 static struct {
-       u32             base;
+       void __iomem    *base;
 
        struct omapfb_mem_desc  mem_desc;
        struct resmap           *res_map[DISPC_MEMTYPE_NUM];
@@ -212,9 +212,9 @@ static void enable_rfbi_mode(int enable)
        dispc_write_reg(DISPC_CONTROL, l);
 
        /* Set bypass mode in RFBI module */
-       l = __raw_readl(io_p2v(RFBI_CONTROL));
+       l = __raw_readl(IO_ADDRESS(RFBI_CONTROL));
        l |= enable ? 0 : (1 << 1);
-       __raw_writel(l, io_p2v(RFBI_CONTROL));
+       __raw_writel(l, IO_ADDRESS(RFBI_CONTROL));
 }
 
 static void set_lcd_data_lines(int data_lines)
@@ -519,8 +519,7 @@ static int omap_dispc_set_scale(int plane,
        if ((unsigned)plane > OMAPFB_PLANE_NUM)
                return -ENODEV;
 
-       if (plane == OMAPFB_PLANE_GFX &&
-           (out_width != orig_width || out_height != orig_height))
+       if (out_width != orig_width || out_height != orig_height)
                return -EINVAL;
 
        enable_lcd_clocks(1);
@@ -858,8 +857,11 @@ EXPORT_SYMBOL(omap_dispc_free_irq);
 
 static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
 {
-       u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
+       u32 stat;
 
+       enable_lcd_clocks(1);
+
+       stat = dispc_read_reg(DISPC_IRQSTATUS);
        if (stat & DISPC_IRQ_FRAMEMASK)
                complete(&dispc.frame_done);
 
@@ -875,25 +877,31 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
 
        dispc_write_reg(DISPC_IRQSTATUS, stat);
 
+       enable_lcd_clocks(0);
+
        return IRQ_HANDLED;
 }
 
 static int get_dss_clocks(void)
 {
-       if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
-               dev_err(dispc.fbdev->dev, "can't get dss_ick\n");
+       char *dss_ick = "dss_ick";
+       char *dss1_fck = cpu_is_omap34xx() ? "dss1_alwon_fck" : "dss1_fck";
+       char *tv_fck = cpu_is_omap34xx() ? "dss_tv_fck" : "dss_54m_fck";
+
+       if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, dss_ick)))) {
+               dev_err(dispc.fbdev->dev, "can't get %s", dss_ick);
                return PTR_ERR(dispc.dss_ick);
        }
 
-       if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
-               dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
+       if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, dss1_fck)))) {
+               dev_err(dispc.fbdev->dev, "can't get %s", dss1_fck);
                clk_put(dispc.dss_ick);
                return PTR_ERR(dispc.dss1_fck);
        }
 
        if (IS_ERR((dispc.dss_54m_fck =
-                               clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
-               dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n");
+                               clk_get(dispc.fbdev->dev, tv_fck)))) {
+               dev_err(dispc.fbdev->dev, "can't get %s", tv_fck);
                clk_put(dispc.dss_ick);
                clk_put(dispc.dss1_fck);
                return PTR_ERR(dispc.dss_54m_fck);
@@ -911,18 +919,13 @@ static void put_dss_clocks(void)
 
 static void enable_lcd_clocks(int enable)
 {
-       if (enable)
+       if (enable) {
+               clk_enable(dispc.dss_ick);
                clk_enable(dispc.dss1_fck);
-       else
+       } else {
                clk_disable(dispc.dss1_fck);
-}
-
-static void enable_interface_clocks(int enable)
-{
-       if (enable)
-               clk_enable(dispc.dss_ick);
-       else
                clk_disable(dispc.dss_ick);
+       }
 }
 
 static void enable_digit_clocks(int enable)
@@ -1349,16 +1352,20 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
 
        memset(&dispc, 0, sizeof(dispc));
 
-       dispc.base = io_p2v(DISPC_BASE);
+       dispc.base = ioremap(DISPC_BASE, SZ_1K);
+       if (!dispc.base) {
+               dev_err(fbdev->dev, "can't ioremap DISPC\n");
+               return -ENOMEM;
+       }
+
        dispc.fbdev = fbdev;
        dispc.ext_mode = ext_mode;
 
        init_completion(&dispc.frame_done);
 
        if ((r = get_dss_clocks()) < 0)
-               return r;
+               goto fail0;
 
-       enable_interface_clocks(1);
        enable_lcd_clocks(1);
 
 #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
@@ -1389,10 +1396,10 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
                enable_digit_clocks(0);
        }
 
-       /* Enable smart idle and autoidle */
-       l = dispc_read_reg(DISPC_CONTROL);
+       /* Enable smart standby/idle, autoidle and wakeup */
+       l = dispc_read_reg(DISPC_SYSCONFIG);
        l &= ~((3 << 12) | (3 << 3));
-       l |= (2 << 12) | (2 << 3) | (1 << 0);
+       l |= (2 << 12) | (2 << 3) | (1 << 2) | (1 << 0);
        dispc_write_reg(DISPC_SYSCONFIG, l);
        omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
 
@@ -1402,7 +1409,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        dispc_write_reg(DISPC_CONFIG, l);
 
        l = dispc_read_reg(DISPC_IRQSTATUS);
-       dispc_write_reg(l, DISPC_IRQSTATUS);
+       dispc_write_reg(DISPC_IRQSTATUS, l);
 
        /* Enable those that we handle always */
        omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
@@ -1414,7 +1421,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
        }
 
        /* L3 firewall setting: enable access to OCM RAM */
-       __raw_writel(0x402000b0, io_p2v(0x680050a0));
+       __raw_writel(0x402000b0, IO_ADDRESS(0x680050a0));
 
        if ((r = alloc_palette_ram()) < 0)
                goto fail2;
@@ -1462,9 +1469,9 @@ fail2:
        free_irq(INT_24XX_DSS_IRQ, fbdev);
 fail1:
        enable_lcd_clocks(0);
-       enable_interface_clocks(0);
        put_dss_clocks();
-
+fail0:
+       iounmap(dispc.base);
        return r;
 }
 
@@ -1479,8 +1486,8 @@ static void omap_dispc_cleanup(void)
        cleanup_fbmem();
        free_palette_ram();
        free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
-       enable_interface_clocks(0);
        put_dss_clocks();
+       iounmap(dispc.base);
 }
 
 const struct lcd_ctrl omap2_int_ctrl = {
index eb1512b56ce86e3c0c54e4da0607d05750b40112..ef720a78f6d513155d38ae1cba4061c966d0d1fa 100644 (file)
@@ -40,4 +40,6 @@ extern void omap_dispc_enable_digit_out(int enable);
 extern int  omap_dispc_request_irq(void (*callback)(void *data), void *data);
 extern void omap_dispc_free_irq(void);
 
+extern const struct lcd_ctrl omap2_int_ctrl;
+
 #endif
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
new file mode 100644 (file)
index 0000000..4a61fa0
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * LCD panel support for the TI 2430SDP board
+ *
+ * Copyright (C) 2007 MontaVista
+ * Author: Hunyue Yau <hyau@mvista.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO       91
+#define SDP2430_LCD_PANEL_ENABLE_GPIO          154
+#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO       24
+#define SDP3430_LCD_PANEL_ENABLE_GPIO          28
+
+static unsigned backlight_gpio;
+static unsigned enable_gpio;
+
+#define LCD_PIXCLOCK_MAX               5400 /* freq 5.4 MHz */
+#define PM_RECEIVER             TWL4030_MODULE_PM_RECEIVER
+#define ENABLE_VAUX2_DEDICATED  0x09
+#define ENABLE_VAUX2_DEV_GRP    0x20
+#define ENABLE_VAUX3_DEDICATED 0x03
+#define ENABLE_VAUX3_DEV_GRP   0x20
+
+#define ENABLE_VPLL2_DEDICATED          0x05
+#define ENABLE_VPLL2_DEV_GRP            0xE0
+#define TWL4030_VPLL2_DEV_GRP           0x33
+#define TWL4030_VPLL2_DEDICATED         0x36
+
+#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+
+
+static int sdp2430_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       if (machine_is_omap_3430sdp()) {
+               enable_gpio    = SDP3430_LCD_PANEL_ENABLE_GPIO;
+               backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
+       } else {
+               enable_gpio    = SDP2430_LCD_PANEL_ENABLE_GPIO;
+               backlight_gpio = SDP2430_LCD_PANEL_BACKLIGHT_GPIO;
+       }
+
+       omap_request_gpio(enable_gpio);                 /* LCD panel */
+       omap_request_gpio(backlight_gpio);              /* LCD backlight */
+       omap_set_gpio_direction(enable_gpio, 0);        /* output */
+       omap_set_gpio_direction(backlight_gpio, 0);     /* output */
+
+       return 0;
+}
+
+static void sdp2430_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int sdp2430_panel_enable(struct lcd_panel *panel)
+{
+       u8 ded_val, ded_reg;
+       u8 grp_val, grp_reg;
+
+       if (machine_is_omap_3430sdp()) {
+               ded_reg = TWL4030_VAUX3_DEDICATED;
+               ded_val = ENABLE_VAUX3_DEDICATED;
+               grp_reg = TWL4030_VAUX3_DEV_GRP;
+               grp_val = ENABLE_VAUX3_DEV_GRP;
+
+               if (system_rev > OMAP3430_REV_ES1_0) {
+                       t2_out(PM_RECEIVER, ENABLE_VPLL2_DEDICATED,
+                                       TWL4030_VPLL2_DEDICATED);
+                       t2_out(PM_RECEIVER, ENABLE_VPLL2_DEV_GRP,
+                                       TWL4030_VPLL2_DEV_GRP);
+               }
+       } else {
+               ded_reg = TWL4030_VAUX2_DEDICATED;
+               ded_val = ENABLE_VAUX2_DEDICATED;
+               grp_reg = TWL4030_VAUX2_DEV_GRP;
+               grp_val = ENABLE_VAUX2_DEV_GRP;
+       }
+               
+       omap_set_gpio_dataout(enable_gpio, 1);
+       omap_set_gpio_dataout(backlight_gpio, 1);
+
+       if (0 != t2_out(PM_RECEIVER, ded_val, ded_reg))
+               return -EIO;
+       if (0 != t2_out(PM_RECEIVER, grp_val, grp_reg))
+               return -EIO;
+
+       return 0;
+}
+
+static void sdp2430_panel_disable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(enable_gpio, 0);
+       omap_set_gpio_dataout(backlight_gpio, 0);
+       if (system_rev > OMAP3430_REV_ES1_0) {
+               t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEDICATED);
+               t2_out(PM_RECEIVER, 0x0, TWL4030_VPLL2_DEV_GRP);
+               mdelay(4);
+       }
+}
+
+static unsigned long sdp2430_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel sdp2430_panel = {
+       .name           = "sdp2430",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .hsw            = 3,            /* hsync_len (4) - 1 */
+       .hfp            = 3,            /* right_margin (4) - 1 */
+       .hbp            = 39,           /* left_margin (40) - 1 */
+       .vsw            = 1,            /* vsync_len (2) - 1 */
+       .vfp            = 2,            /* lower_margin */
+       .vbp            = 7,            /* upper_margin (8) - 1 */
+
+       .pixel_clock    = LCD_PIXCLOCK_MAX,
+
+       .init           = sdp2430_panel_init,
+       .cleanup        = sdp2430_panel_cleanup,
+       .enable         = sdp2430_panel_enable,
+       .disable        = sdp2430_panel_disable,
+       .get_caps       = sdp2430_panel_get_caps,
+};
+
+static int sdp2430_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&sdp2430_panel);
+       return 0;
+}
+
+static int sdp2430_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int sdp2430_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int sdp2430_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver sdp2430_panel_driver = {
+       .probe          = sdp2430_panel_probe,
+       .remove         = sdp2430_panel_remove,
+       .suspend        = sdp2430_panel_suspend,
+       .resume         = sdp2430_panel_resume,
+       .driver         = {
+               .name   = "sdp2430_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sdp2430_panel_drv_init(void)
+{
+       return platform_driver_register(&sdp2430_panel_driver);
+}
+
+static void __exit sdp2430_panel_drv_exit(void)
+{
+       platform_driver_unregister(&sdp2430_panel_driver);
+}
+
+module_init(sdp2430_panel_drv_init);
+module_exit(sdp2430_panel_drv_exit);
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..3fd5342
--- /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 <mach/board-ams-delta.h>
+#include <mach/hardware.h>
+#include <mach/omapfb.h>
+
+#define AMS_DELTA_DEFAULT_CONTRAST     112
+
+static int ams_delta_panel_init(struct lcd_panel *panel,
+               struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void ams_delta_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int ams_delta_panel_enable(struct lcd_panel *panel)
+{
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
+                       AMS_DELTA_LATCH2_LCD_NDISP);
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
+                       AMS_DELTA_LATCH2_LCD_VBLEN);
+
+       omap_writeb(1, OMAP_PWL_CLK_ENABLE);
+       omap_writeb(AMS_DELTA_DEFAULT_CONTRAST, OMAP_PWL_ENABLE);
+
+       return 0;
+}
+
+static void ams_delta_panel_disable(struct lcd_panel *panel)
+{
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
+       ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+}
+
+static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static struct lcd_panel ams_delta_panel = {
+       .name           = "ams-delta",
+       .config         = 0,
+
+       .bpp            = 12,
+       .data_lines     = 16,
+       .x_res          = 480,
+       .y_res          = 320,
+       .pixel_clock    = 4687,
+       .hsw            = 3,
+       .hfp            = 1,
+       .hbp            = 1,
+       .vsw            = 1,
+       .vfp            = 0,
+       .vbp            = 0,
+       .pcd            = 0,
+       .acb            = 37,
+
+       .init           = ams_delta_panel_init,
+       .cleanup        = ams_delta_panel_cleanup,
+       .enable         = ams_delta_panel_enable,
+       .disable        = ams_delta_panel_disable,
+       .get_caps       = ams_delta_panel_get_caps,
+};
+
+static int ams_delta_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&ams_delta_panel);
+       return 0;
+}
+
+static int ams_delta_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int ams_delta_panel_suspend(struct platform_device *pdev,
+               pm_message_t mesg)
+{
+       return 0;
+}
+
+static int ams_delta_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver ams_delta_panel_driver = {
+       .probe          = ams_delta_panel_probe,
+       .remove         = ams_delta_panel_remove,
+       .suspend        = ams_delta_panel_suspend,
+       .resume         = ams_delta_panel_resume,
+       .driver         = {
+               .name   = "lcd_ams_delta",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int ams_delta_panel_drv_init(void)
+{
+       return platform_driver_register(&ams_delta_panel_driver);
+}
+
+static void ams_delta_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&ams_delta_panel_driver);
+}
+
+module_init(ams_delta_panel_drv_init);
+module_exit(ams_delta_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
new file mode 100644 (file)
index 0000000..beae5d9
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * LCD panel support for the Samsung OMAP2 Apollon board
+ *
+ * Copyright (C) 2005,2006 Samsung Electronics
+ * Author: Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Derived from drivers/video/omap/lcd-h4.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+
+/* #define USE_35INCH_LCD 1 */
+
+static int apollon_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       /* configure LCD PWR_EN */
+       omap_cfg_reg(M21_242X_GPIO11);
+       return 0;
+}
+
+static void apollon_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int apollon_panel_enable(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static void apollon_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long apollon_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel apollon_panel = {
+       .name           = "apollon",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC,
+
+       .bpp            = 16,
+       .data_lines     = 18,
+#ifdef USE_35INCH_LCD
+       .x_res          = 240,
+       .y_res          = 320,
+       .hsw            = 2,
+       .hfp            = 3,
+       .hbp            = 9,
+       .vsw            = 4,
+       .vfp            = 3,
+       .vbp            = 5,
+#else
+       .x_res          = 480,
+       .y_res          = 272,
+       .hsw            = 41,
+       .hfp            = 2,
+       .hbp            = 2,
+       .vsw            = 10,
+       .vfp            = 2,
+       .vbp            = 2,
+#endif
+       .pixel_clock    = 6250,
+
+       .init           = apollon_panel_init,
+       .cleanup        = apollon_panel_cleanup,
+       .enable         = apollon_panel_enable,
+       .disable        = apollon_panel_disable,
+       .get_caps       = apollon_panel_get_caps,
+};
+
+static int apollon_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&apollon_panel);
+       return 0;
+}
+
+static int apollon_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int apollon_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int apollon_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver apollon_panel_driver = {
+       .probe          = apollon_panel_probe,
+       .remove         = apollon_panel_remove,
+       .suspend        = apollon_panel_suspend,
+       .resume         = apollon_panel_resume,
+       .driver         = {
+               .name   = "apollon_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init apollon_panel_drv_init(void)
+{
+       return platform_driver_register(&apollon_panel_driver);
+}
+
+static void __exit apollon_panel_drv_exit(void)
+{
+       platform_driver_unregister(&apollon_panel_driver);
+}
+
+module_init(apollon_panel_drv_init);
+module_exit(apollon_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_h2.c b/drivers/video/omap/lcd_h2.c
new file mode 100644 (file)
index 0000000..96b4816
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * LCD panel support for the TI OMAP H2 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/tsc2101.h>
+
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+
+static struct {
+       struct platform_device  *lcd_dev;
+       struct spi_device       *tsc2101_dev;
+} h2_panel_dev;
+
+static int h2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void h2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h2_panel_enable(struct lcd_panel *panel)
+{
+       int r;
+
+       /*
+        * Assert LCD_EN, BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and asserted
+        */
+       r = tsc2101_write_sync(h2_panel_dev.tsc2101_dev, 2, 0x23, 0xcc00);
+       if (r < 0)
+               dev_err(&h2_panel_dev.lcd_dev->dev,
+                       "failed to enable LCD panel\n");
+
+       return r;
+}
+
+static void h2_panel_disable(struct lcd_panel *panel)
+{
+       /*
+        * Deassert LCD_EN and BKLIGHT_EN pins on LCD panel
+        * page2, GPIO config reg, GPIO(0,1) to out and deasserted
+        */
+       if (tsc2101_write_sync(h2_panel_dev.tsc2101_dev, 2, 0x23, 0x8800))
+               dev_err(&h2_panel_dev.lcd_dev->dev,
+                       "failed to disable LCD panel\n");
+}
+
+static unsigned long h2_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel h2_panel = {
+       .name           = "h2",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 16,
+       .x_res          = 240,
+       .y_res          = 320,
+       .pixel_clock    = 5000,
+       .hsw            = 12,
+       .hfp            = 12,
+       .hbp            = 46,
+       .vsw            = 1,
+       .vfp            = 1,
+       .vbp            = 0,
+
+       .init           = h2_panel_init,
+       .cleanup        = h2_panel_cleanup,
+       .enable         = h2_panel_enable,
+       .disable        = h2_panel_disable,
+       .get_caps       = h2_panel_get_caps,
+};
+
+static int h2_panel_probe(struct platform_device *pdev)
+{
+       struct spi_device *tsc2101;
+
+       tsc2101 = pdev->dev.platform_data;
+       if (tsc2101 == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -ENODEV;
+       }
+       if (strncmp(tsc2101->modalias, "tsc2101", 8) != 0) {
+               dev_err(&pdev->dev, "tsc2101 not found\n");
+               return -EINVAL;
+       }
+       h2_panel_dev.lcd_dev = pdev;
+       h2_panel_dev.tsc2101_dev = tsc2101;
+       omapfb_register_panel(&h2_panel);
+       return 0;
+}
+
+static int h2_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int h2_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       return 0;
+}
+
+static int h2_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver h2_panel_driver = {
+       .probe          = h2_panel_probe,
+       .remove         = h2_panel_remove,
+       .suspend        = h2_panel_suspend,
+       .resume         = h2_panel_resume,
+       .driver         = {
+               .name   = "lcd_h2",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int h2_panel_drv_init(void)
+{
+       return platform_driver_register(&h2_panel_driver);
+}
+
+static void h2_panel_drv_cleanup(void)
+{
+       platform_driver_unregister(&h2_panel_driver);
+}
+
+module_init(h2_panel_drv_init);
+module_exit(h2_panel_drv_cleanup);
+
index 88c19d424ef769f32f1fe9fa23996b7214f4e9ec..6ff56430341b862a21dbbbaec416b13f17e484a1 100644 (file)
@@ -47,7 +47,7 @@ static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
        return 0;
 }
 
-struct lcd_panel h4_panel = {
+static struct lcd_panel h4_panel = {
        .name           = "h4",
        .config         = OMAP_LCDC_PANEL_TFT,
 
@@ -91,7 +91,7 @@ static int h4_panel_resume(struct platform_device *pdev)
        return 0;
 }
 
-struct platform_driver h4_panel_driver = {
+static struct platform_driver h4_panel_driver = {
        .probe          = h4_panel_probe,
        .remove         = h4_panel_remove,
        .suspend        = h4_panel_suspend,
index 6a42c6a0cd9991466b1a77781873e05b3171fcd8..4c4f7ee6d733a66e739c6be1e9cd65ad370f8633 100644 (file)
@@ -32,43 +32,43 @@ static int innovator1610_panel_init(struct lcd_panel *panel,
 {
        int r = 0;
 
-       if (omap_request_gpio(14)) {
+       if (gpio_request(14, "lcd_en0")) {
                pr_err(MODULE_NAME ": can't request GPIO 14\n");
                r = -1;
                goto exit;
        }
-       if (omap_request_gpio(15)) {
+       if (gpio_request(15, "lcd_en1")) {
                pr_err(MODULE_NAME ": can't request GPIO 15\n");
-               omap_free_gpio(14);
+               gpio_free(14);
                r = -1;
                goto exit;
        }
        /* configure GPIO(14, 15) as outputs */
-       omap_set_gpio_direction(14, 0);
-       omap_set_gpio_direction(15, 0);
+       gpio_direction_output(14, 0);
+       gpio_direction_output(15, 0);
 exit:
        return r;
 }
 
 static void innovator1610_panel_cleanup(struct lcd_panel *panel)
 {
-       omap_free_gpio(15);
-       omap_free_gpio(14);
+       gpio_free(15);
+       gpio_free(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);
+       gpio_set_value(14, 1);
+       gpio_set_value(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);
+       gpio_set_value(14, 0);
+       gpio_set_value(15, 0);
 }
 
 static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
new file mode 100644 (file)
index 0000000..1895997
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * LCD driver for MIPI DBI-C / DCS compatible LCDs
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#include <mach/omapfb.h>
+#include <mach/lcd_mipid.h>
+
+#include "../../cbus/tahvo.h"
+
+#define MIPID_MODULE_NAME              "lcd_mipid"
+
+#define MIPID_CMD_READ_DISP_ID         0x04
+#define MIPID_CMD_READ_RED             0x06
+#define MIPID_CMD_READ_GREEN           0x07
+#define MIPID_CMD_READ_BLUE            0x08
+#define MIPID_CMD_READ_DISP_STATUS     0x09
+#define MIPID_CMD_RDDSDR               0x0F
+#define MIPID_CMD_SLEEP_IN             0x10
+#define MIPID_CMD_SLEEP_OUT            0x11
+#define MIPID_CMD_DISP_OFF             0x28
+#define MIPID_CMD_DISP_ON              0x29
+
+#define MIPID_VER_LPH8923              3
+#define MIPID_VER_LS041Y3              4
+
+#define MIPID_ESD_CHECK_PERIOD         msecs_to_jiffies(5000)
+
+#define to_mipid_device(p)             container_of(p, struct mipid_device, \
+                                               panel)
+struct mipid_device {
+       int             enabled;
+       int             model;
+       int             revision;
+       u8              display_id[3];
+       unsigned int    saved_bklight_level;
+       unsigned long   hw_guard_end;           /* next value of jiffies
+                                                  when we can issue the
+                                                  next sleep in/out command */
+       unsigned long   hw_guard_wait;          /* max guard time in jiffies */
+
+       struct omapfb_device    *fbdev;
+       struct spi_device       *spi;
+       struct mutex            mutex;
+       struct lcd_panel        panel;
+
+       struct workqueue_struct *esd_wq;
+       struct delayed_work     esd_work;
+       void                    (*esd_check)(struct mipid_device *m);
+};
+
+static void mipid_transfer(struct mipid_device *md, int cmd, const u8 *wbuf,
+                          int wlen, u8 *rbuf, int rlen)
+{
+       struct spi_message      m;
+       struct spi_transfer     *x, xfer[4];
+       u16                     w;
+       int                     r;
+
+       BUG_ON(md->spi == NULL);
+
+       spi_message_init(&m);
+
+       memset(xfer, 0, sizeof(xfer));
+       x = &xfer[0];
+
+       cmd &=  0xff;
+       x->tx_buf       = &cmd;
+       x->bits_per_word= 9;
+       x->len          = 2;
+       spi_message_add_tail(x, &m);
+
+       if (wlen) {
+               x++;
+               x->tx_buf       = wbuf;
+               x->len          = wlen;
+               x->bits_per_word= 9;
+               spi_message_add_tail(x, &m);
+       }
+
+       if (rlen) {
+               x++;
+               x->rx_buf       = &w;
+               x->len          = 1;
+               spi_message_add_tail(x, &m);
+
+               if (rlen > 1) {
+                       /* Arrange for the extra clock before the first
+                        * data bit.
+                        */
+                       x->bits_per_word = 9;
+                       x->len           = 2;
+
+                       x++;
+                       x->rx_buf        = &rbuf[1];
+                       x->len           = rlen - 1;
+                       spi_message_add_tail(x, &m);
+               }
+       }
+
+       r = spi_sync(md->spi, &m);
+       if (r < 0)
+               dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+
+       if (rlen)
+               rbuf[0] = w & 0xff;
+}
+
+static inline void mipid_cmd(struct mipid_device *md, int cmd)
+{
+       mipid_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void mipid_write(struct mipid_device *md,
+                              int reg, const u8 *buf, int len)
+{
+       mipid_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void mipid_read(struct mipid_device *md,
+                             int reg, u8 *buf, int len)
+{
+       mipid_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void set_data_lines(struct mipid_device *md, int data_lines)
+{
+       u16 par;
+
+       switch (data_lines) {
+       case 16:
+               par = 0x150;
+               break;
+       case 18:
+               par = 0x160;
+               break;
+       case 24:
+               par = 0x170;
+               break;
+       }
+       mipid_write(md, 0x3a, (u8 *)&par, 2);
+}
+
+static void send_init_string(struct mipid_device *md)
+{
+       u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
+
+       mipid_write(md, 0xc2, (u8 *)initpar, sizeof(initpar));
+       set_data_lines(md, md->panel.data_lines);
+}
+
+static void hw_guard_start(struct mipid_device *md, int guard_msec)
+{
+       md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+       md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct mipid_device *md)
+{
+       unsigned long wait = md->hw_guard_end - jiffies;
+
+       if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(wait);
+       }
+}
+
+static void set_sleep_mode(struct mipid_device *md, int on)
+{
+       int cmd, sleep_time = 50;
+
+       if (on)
+               cmd = MIPID_CMD_SLEEP_IN;
+       else
+               cmd = MIPID_CMD_SLEEP_OUT;
+       hw_guard_wait(md);
+       mipid_cmd(md, cmd);
+       hw_guard_start(md, 120);
+       /*
+        * When we enable the panel, it seems we _have_ to sleep
+        * 120 ms before sending the init string. When disabling the
+        * panel we'll sleep for the duration of 2 frames, so that the
+        * controller can still provide the PCLK,HS,VS signals. */
+       if (!on)
+               sleep_time = 120;
+       msleep(sleep_time);
+}
+
+static void set_display_state(struct mipid_device *md, int enabled)
+{
+       int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+       mipid_cmd(md, cmd);
+}
+
+static int mipid_set_bklight_level(struct lcd_panel *panel, unsigned int level)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       if (level > tahvo_get_max_backlight_level())
+               return -EINVAL;
+       if (!md->enabled) {
+               md->saved_bklight_level = level;
+               return 0;
+       }
+       tahvo_set_backlight_level(level);
+
+       return 0;
+}
+
+static unsigned int mipid_get_bklight_level(struct lcd_panel *panel)
+{
+       return tahvo_get_backlight_level();
+}
+
+static unsigned int mipid_get_bklight_max(struct lcd_panel *panel)
+{
+       return tahvo_get_max_backlight_level();
+}
+
+
+static unsigned long mipid_get_caps(struct lcd_panel *panel)
+{
+       return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+static u16 read_first_pixel(struct mipid_device *md)
+{
+       u16 pixel;
+       u8 red, green, blue;
+
+       mutex_lock(&md->mutex);
+       mipid_read(md, MIPID_CMD_READ_RED, &red, 1);
+       mipid_read(md, MIPID_CMD_READ_GREEN, &green, 1);
+       mipid_read(md, MIPID_CMD_READ_BLUE, &blue, 1);
+       mutex_unlock(&md->mutex);
+
+       switch (md->panel.data_lines) {
+       case 16:
+               pixel = ((red >> 1) << 11) | (green << 5) | (blue >> 1);
+               break;
+       case 24:
+               /* 24 bit -> 16 bit */
+               pixel = ((red >> 3) << 11) | ((green >> 2) << 5) |
+                       (blue >> 3);
+               break;
+       default:
+               BUG();
+       }
+
+       return pixel;
+}
+
+static int mipid_run_test(struct lcd_panel *panel, int test_num)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+       static const u16 test_values[4] = {
+               0x0000, 0xffff, 0xaaaa, 0x5555,
+       };
+       int i;
+
+       if (test_num != MIPID_TEST_RGB_LINES)
+               return MIPID_TEST_INVALID;
+
+       for (i = 0; i < ARRAY_SIZE(test_values); i++) {
+               int delay;
+               unsigned long tmo;
+
+               omapfb_write_first_pixel(md->fbdev, test_values[i]);
+               tmo = jiffies + msecs_to_jiffies(100);
+               delay = 25;
+               while (1) {
+                       u16 pixel;
+
+                       msleep(delay);
+                       pixel = read_first_pixel(md);
+                       if (pixel == test_values[i])
+                               break;
+                       if (time_after(jiffies, tmo)) {
+                               dev_err(&md->spi->dev,
+                                       "MIPI LCD RGB I/F test failed: "
+                                       "expecting %04x, got %04x\n",
+                                       test_values[i], pixel);
+                               return MIPID_TEST_FAILED;
+                       }
+                       delay = 10;
+               }
+       }
+
+       return 0;
+}
+
+static void ls041y3_esd_recover(struct mipid_device *md)
+{
+       dev_err(&md->spi->dev, "performing LCD ESD recovery\n");
+       set_sleep_mode(md, 1);
+       set_sleep_mode(md, 0);
+}
+
+static void ls041y3_esd_check_mode1(struct mipid_device *md)
+{
+       u8 state1, state2;
+
+       mipid_read(md, MIPID_CMD_RDDSDR, &state1, 1);
+       set_sleep_mode(md, 0);
+       mipid_read(md, MIPID_CMD_RDDSDR, &state2, 1);
+       dev_dbg(&md->spi->dev, "ESD mode 1 state1 %02x state2 %02x\n",
+               state1, state2);
+       /* Each sleep out command will trigger a self diagnostic and flip
+       * Bit6 if the test passes.
+       */
+       if (!((state1 ^ state2) & (1 << 6)))
+               ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check_mode2(struct mipid_device *md)
+{
+       int i;
+       u8 rbuf[2];
+       static const struct {
+               int     cmd;
+               int     wlen;
+               u16     wbuf[3];
+       } *rd, rd_ctrl[7] = {
+               { 0xb0, 4, { 0x0101, 0x01fe, } },
+               { 0xb1, 4, { 0x01de, 0x0121, } },
+               { 0xc2, 4, { 0x0100, 0x0100, } },
+               { 0xbd, 2, { 0x0100, } },
+               { 0xc2, 4, { 0x01fc, 0x0103, } },
+               { 0xb4, 0, },
+               { 0x00, 0, },
+       };
+
+       rd = rd_ctrl;
+       for (i = 0; i < 3; i++, rd++)
+               mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+
+       udelay(10);
+       mipid_read(md, rd->cmd, rbuf, 2);
+       rd++;
+
+       for (i = 0; i < 3; i++, rd++) {
+               udelay(10);
+               mipid_write(md, rd->cmd, (u8 *)rd->wbuf, rd->wlen);
+       }
+
+       dev_dbg(&md->spi->dev, "ESD mode 2 state %02x\n", rbuf[1]);
+       if (rbuf[1] == 0x00)
+               ls041y3_esd_recover(md);
+}
+
+static void ls041y3_esd_check(struct mipid_device *md)
+{
+       ls041y3_esd_check_mode1(md);
+       if (md->revision >= 0x88)
+               ls041y3_esd_check_mode2(md);
+}
+
+static void mipid_esd_start_check(struct mipid_device *md)
+{
+       if (md->esd_check != NULL)
+               queue_delayed_work(md->esd_wq, &md->esd_work,
+                                  MIPID_ESD_CHECK_PERIOD);
+}
+
+static void mipid_esd_stop_check(struct mipid_device *md)
+{
+       if (md->esd_check != NULL)
+               cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work);
+}
+
+static void mipid_esd_work(struct work_struct *work)
+{
+       struct mipid_device *md = container_of(work, struct mipid_device, esd_work.work);
+
+       mutex_lock(&md->mutex);
+       md->esd_check(md);
+       mutex_unlock(&md->mutex);
+       mipid_esd_start_check(md);
+}
+
+static int mipid_enable(struct lcd_panel *panel)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       mutex_lock(&md->mutex);
+
+       if (md->enabled) {
+               mutex_unlock(&md->mutex);
+               return 0;
+       }
+       set_sleep_mode(md, 0);
+       md->enabled = 1;
+       send_init_string(md);
+       set_display_state(md, 1);
+       mipid_set_bklight_level(panel, md->saved_bklight_level);
+       mipid_esd_start_check(md);
+
+       mutex_unlock(&md->mutex);
+       return 0;
+}
+
+static void mipid_disable(struct lcd_panel *panel)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       /*
+        * A final ESD work might be called before returning,
+        * so do this without holding the lock.
+        */
+       mipid_esd_stop_check(md);
+       mutex_lock(&md->mutex);
+
+       if (!md->enabled) {
+               mutex_unlock(&md->mutex);
+               return;
+       }
+       md->saved_bklight_level = mipid_get_bklight_level(panel);
+       mipid_set_bklight_level(panel, 0);
+       set_display_state(md, 0);
+       set_sleep_mode(md, 1);
+       md->enabled = 0;
+
+       mutex_unlock(&md->mutex);
+}
+
+static int panel_enabled(struct mipid_device *md)
+{
+       u32 disp_status;
+       int enabled;
+
+       mipid_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+       disp_status = __be32_to_cpu(disp_status);
+       enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+       dev_dbg(&md->spi->dev,
+               "LCD panel %senabled by bootloader (status 0x%04x)\n",
+               enabled ? "" : "not ", disp_status);
+       return enabled;
+}
+
+static int mipid_init(struct lcd_panel *panel,
+                           struct omapfb_device *fbdev)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       md->fbdev = fbdev;
+       md->esd_wq = create_singlethread_workqueue("mipid_esd");
+       if (md->esd_wq == NULL) {
+               dev_err(&md->spi->dev, "can't create ESD workqueue\n");
+               return -ENOMEM;
+       }
+       INIT_DELAYED_WORK(&md->esd_work, mipid_esd_work);
+       mutex_init(&md->mutex);
+
+       md->enabled = panel_enabled(md);
+
+       if (md->enabled)
+               mipid_esd_start_check(md);
+       else
+               md->saved_bklight_level = mipid_get_bklight_level(panel);
+
+       return 0;
+}
+
+static void mipid_cleanup(struct lcd_panel *panel)
+{
+       struct mipid_device *md = to_mipid_device(panel);
+
+       if (md->enabled)
+               mipid_esd_stop_check(md);
+       destroy_workqueue(md->esd_wq);
+}
+
+static struct lcd_panel mipid_panel = {
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .x_res          = 800,
+       .y_res          = 480,
+       .pixel_clock    = 21940,
+       .hsw            = 50,
+       .hfp            = 20,
+       .hbp            = 15,
+       .vsw            = 2,
+       .vfp            = 1,
+       .vbp            = 3,
+
+       .init           = mipid_init,
+       .cleanup        = mipid_cleanup,
+       .enable         = mipid_enable,
+       .disable        = mipid_disable,
+       .get_caps       = mipid_get_caps,
+       .set_bklight_level= mipid_set_bklight_level,
+       .get_bklight_level= mipid_get_bklight_level,
+       .get_bklight_max= mipid_get_bklight_max,
+       .run_test       = mipid_run_test,
+};
+
+static int mipid_detect(struct mipid_device *md)
+{
+       struct mipid_platform_data *pdata;
+
+       pdata = md->spi->dev.platform_data;
+       if (pdata == NULL) {
+               dev_err(&md->spi->dev, "missing platform data\n");
+               return -ENOENT;
+       }
+
+       mipid_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+       dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+               md->display_id[0], md->display_id[1], md->display_id[2]);
+
+       switch (md->display_id[0]) {
+       case 0x45:
+               md->model = MIPID_VER_LPH8923;
+               md->panel.name = "lph8923";
+               break;
+       case 0x83:
+               md->model = MIPID_VER_LS041Y3;
+               md->panel.name = "ls041y3";
+               md->esd_check = ls041y3_esd_check;
+               break;
+       default:
+               md->panel.name = "unknown";
+               dev_err(&md->spi->dev, "invalid display ID\n");
+               return -ENODEV;
+       }
+
+       md->revision = md->display_id[1];
+       md->panel.data_lines = pdata->data_lines;
+       pr_info("omapfb: %s rev %02x LCD detected\n",
+                       md->panel.name, md->revision);
+
+       return 0;
+}
+
+static int mipid_spi_probe(struct spi_device *spi)
+{
+       struct mipid_device *md;
+       int r;
+
+       md = kzalloc(sizeof(*md), GFP_KERNEL);
+       if (md == NULL) {
+               dev_err(&spi->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       spi->mode = SPI_MODE_0;
+       md->spi = spi;
+       dev_set_drvdata(&spi->dev, md);
+       md->panel = mipid_panel;
+
+       r = mipid_detect(md);
+       if (r < 0)
+               return r;
+
+       omapfb_register_panel(&md->panel);
+
+       return 0;
+}
+
+static int mipid_spi_remove(struct spi_device *spi)
+{
+       struct mipid_device *md = dev_get_drvdata(&spi->dev);
+
+       mipid_disable(&md->panel);
+       kfree(md);
+
+       return 0;
+}
+
+static struct spi_driver mipid_spi_driver = {
+       .driver = {
+               .name   = MIPID_MODULE_NAME,
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = mipid_spi_probe,
+       .remove = __devexit_p(mipid_spi_remove),
+};
+
+static int mipid_drv_init(void)
+{
+       spi_register_driver(&mipid_spi_driver);
+
+       return 0;
+}
+module_init(mipid_drv_init);
+
+static void mipid_drv_cleanup(void)
+{
+       spi_unregister_driver(&mipid_spi_driver);
+}
+module_exit(mipid_drv_cleanup);
+
+MODULE_DESCRIPTION("MIPI display driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
new file mode 100644 (file)
index 0000000..8a0105e
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * LCD panel support for the MISTRAL OMAP2EVM board
+ *
+ * Author: Arun C <arunedarath@mistralsolutions.com>
+ *
+ * Derived from drivers/video/omap/lcd_omap3evm.c
+ * Derived from drivers/video/omap/lcd-apollon.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO  154
+#define LCD_PANEL_LR           128
+#define LCD_PANEL_UD           129
+#define LCD_PANEL_INI          152
+#define LCD_PANEL_QVGA         148
+#define LCD_PANEL_RESB         153
+
+#define LCD_XRES               480
+#define LCD_YRES               640
+#define LCD_PIXCLOCK_MAX       20000 /* in kHz */
+
+#define TWL_LED_LEDEN          0x00
+#define TWL_PWMA_PWMAON                0x00
+#define TWL_PWMA_PWMAOFF       0x01
+
+static unsigned int bklight_level;
+
+static int omap2evm_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       omap_request_gpio(LCD_PANEL_ENABLE_GPIO);
+       omap_request_gpio(LCD_PANEL_LR);
+       omap_request_gpio(LCD_PANEL_UD);
+       omap_request_gpio(LCD_PANEL_INI);
+       omap_request_gpio(LCD_PANEL_QVGA);
+       omap_request_gpio(LCD_PANEL_RESB);
+
+       omap_set_gpio_direction(LCD_PANEL_ENABLE_GPIO, 0);
+       omap_set_gpio_direction(LCD_PANEL_LR, 0);
+       omap_set_gpio_direction(LCD_PANEL_UD, 0);
+       omap_set_gpio_direction(LCD_PANEL_INI, 0);
+       omap_set_gpio_direction(LCD_PANEL_QVGA, 0);
+       omap_set_gpio_direction(LCD_PANEL_RESB, 0);
+
+       omap_set_gpio_dataout(LCD_PANEL_RESB, 1);
+       omap_set_gpio_dataout(LCD_PANEL_INI, 1);
+       omap_set_gpio_dataout(LCD_PANEL_QVGA, 0);
+       omap_set_gpio_dataout(LCD_PANEL_LR, 1);
+       omap_set_gpio_dataout(LCD_PANEL_UD, 1);
+
+       twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+       bklight_level = 100;
+
+       return 0;
+}
+
+static void omap2evm_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap2evm_panel_enable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 0);
+       return 0;
+}
+
+static void omap2evm_panel_disable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 1);
+}
+
+static unsigned long omap2evm_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static int omap2evm_bklight_setlevel(struct lcd_panel *panel,
+                                               unsigned int level)
+{
+       u8 c;
+       if ((level >= 0) && (level <= 100)) {
+               c = (125 * (100 - level)) / 100 + 2;
+               twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+               bklight_level = level;
+       }
+       return 0;
+}
+
+static unsigned int omap2evm_bklight_getlevel(struct lcd_panel *panel)
+{
+       return bklight_level;
+}
+
+static unsigned int omap2evm_bklight_getmaxlevel(struct lcd_panel *panel)
+{
+       return 100;
+}
+
+struct lcd_panel omap2evm_panel = {
+       .name           = "omap2evm",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC,
+
+       .bpp            = 16,
+       .data_lines     = 18,
+       .x_res          = LCD_XRES,
+       .y_res          = LCD_YRES,
+       .hsw            = 3,
+       .hfp            = 0,
+       .hbp            = 28,
+       .vsw            = 2,
+       .vfp            = 1,
+       .vbp            = 0,
+
+       .pixel_clock    = LCD_PIXCLOCK_MAX,
+
+       .init           = omap2evm_panel_init,
+       .cleanup        = omap2evm_panel_cleanup,
+       .enable         = omap2evm_panel_enable,
+       .disable        = omap2evm_panel_disable,
+       .get_caps       = omap2evm_panel_get_caps,
+       .set_bklight_level      = omap2evm_bklight_setlevel,
+       .get_bklight_level      = omap2evm_bklight_getlevel,
+       .get_bklight_max        = omap2evm_bklight_getmaxlevel,
+};
+
+static int omap2evm_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&omap2evm_panel);
+       return 0;
+}
+
+static int omap2evm_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int omap2evm_panel_suspend(struct platform_device *pdev,
+                                  pm_message_t mesg)
+{
+       return 0;
+}
+
+static int omap2evm_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver omap2evm_panel_driver = {
+       .probe          = omap2evm_panel_probe,
+       .remove         = omap2evm_panel_remove,
+       .suspend        = omap2evm_panel_suspend,
+       .resume         = omap2evm_panel_resume,
+       .driver         = {
+               .name   = "omap2evm_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap2evm_panel_drv_init(void)
+{
+       return platform_driver_register(&omap2evm_panel_driver);
+}
+
+static void __exit omap2evm_panel_drv_exit(void)
+{
+       platform_driver_unregister(&omap2evm_panel_driver);
+}
+
+module_init(omap2evm_panel_drv_init);
+module_exit(omap2evm_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
new file mode 100644 (file)
index 0000000..dc59f39
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * LCD panel support for the TI OMAP3 Beagle board
+ *
+ * Author: Koen Kooi <koen@openembedded.org>
+ *
+ * Derived from drivers/video/omap/lcd-omap3evm.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO       170
+
+#define LCD_XRES               1024    
+#define LCD_YRES               768
+#define LCD_PIXCLOCK           64000 /* in kHz */
+
+static int omap3beagle_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       omap_request_gpio(LCD_PANEL_ENABLE_GPIO);
+       return 0;
+}
+
+static void omap3beagle_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap3beagle_panel_enable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 1);
+       return 0;
+}
+
+static void omap3beagle_panel_disable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 0);
+}
+
+static unsigned long omap3beagle_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel omap3beagle_panel = {
+       .name           = "omap3beagle",
+       .config         = OMAP_LCDC_PANEL_TFT,
+
+       .bpp            = 16,
+       .data_lines     = 24,
+       .x_res          = LCD_XRES,
+       .y_res          = LCD_YRES,
+       .hsw            = 3,            /* hsync_len (4) - 1 */
+       .hfp            = 3,            /* right_margin (4) - 1 */
+       .hbp            = 39,           /* left_margin (40) - 1 */
+       .vsw            = 1,            /* vsync_len (2) - 1 */
+       .vfp            = 2,            /* lower_margin */
+       .vbp            = 7,            /* upper_margin (8) - 1 */
+
+       .pixel_clock    = LCD_PIXCLOCK,
+
+       .init           = omap3beagle_panel_init,
+       .cleanup        = omap3beagle_panel_cleanup,
+       .enable         = omap3beagle_panel_enable,
+       .disable        = omap3beagle_panel_disable,
+       .get_caps       = omap3beagle_panel_get_caps,
+};
+
+static int omap3beagle_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&omap3beagle_panel);
+       return 0;
+}
+
+static int omap3beagle_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int omap3beagle_panel_suspend(struct platform_device *pdev,
+                                  pm_message_t mesg)
+{
+       return 0;
+}
+
+static int omap3beagle_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver omap3beagle_panel_driver = {
+       .probe          = omap3beagle_panel_probe,
+       .remove         = omap3beagle_panel_remove,
+       .suspend        = omap3beagle_panel_suspend,
+       .resume         = omap3beagle_panel_resume,
+       .driver         = {
+               .name   = "omap3beagle_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap3beagle_panel_drv_init(void)
+{
+       return platform_driver_register(&omap3beagle_panel_driver);
+}
+
+static void __exit omap3beagle_panel_drv_exit(void)
+{
+       platform_driver_unregister(&omap3beagle_panel_driver);
+}
+
+module_init(omap3beagle_panel_drv_init);
+module_exit(omap3beagle_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
new file mode 100644 (file)
index 0000000..a564ca5
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * LCD panel support for the TI OMAP3 EVM board
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_PANEL_ENABLE_GPIO       153
+#define LCD_PANEL_LR                2
+#define LCD_PANEL_UD                3
+#define LCD_PANEL_INI               152
+#define LCD_PANEL_QVGA              154
+#define LCD_PANEL_RESB              155
+
+#define LCD_XRES               480
+#define LCD_YRES               640
+#define LCD_PIXCLOCK           26000 /* in kHz  */
+
+#define ENABLE_VDAC_DEDICATED  0x03
+#define ENABLE_VDAC_DEV_GRP    0x20
+#define ENABLE_VPLL2_DEDICATED 0x05
+#define ENABLE_VPLL2_DEV_GRP   0xE0
+
+#define TWL_LED_LEDEN          0x00
+#define TWL_PWMA_PWMAON                0x00
+#define TWL_PWMA_PWMAOFF       0x01
+
+static unsigned int bklight_level;
+
+static int omap3evm_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       omap_request_gpio(LCD_PANEL_LR);
+       omap_request_gpio(LCD_PANEL_UD);
+       omap_request_gpio(LCD_PANEL_INI);
+       omap_request_gpio(LCD_PANEL_RESB);
+       omap_request_gpio(LCD_PANEL_QVGA);
+
+       omap_set_gpio_direction(LCD_PANEL_LR, 0);
+       omap_set_gpio_direction(LCD_PANEL_UD, 0);
+       omap_set_gpio_direction(LCD_PANEL_INI, 0);
+       omap_set_gpio_direction(LCD_PANEL_RESB, 0);
+       omap_set_gpio_direction(LCD_PANEL_QVGA, 0);
+
+       twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
+       twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
+       bklight_level = 100;
+
+       omap_set_gpio_dataout(LCD_PANEL_RESB, 1);
+       omap_set_gpio_dataout(LCD_PANEL_INI, 1);
+       omap_set_gpio_dataout(LCD_PANEL_QVGA, 0);
+       omap_set_gpio_dataout(LCD_PANEL_LR, 1);
+       omap_set_gpio_dataout(LCD_PANEL_UD, 1);
+
+       return 0;
+}
+
+static void omap3evm_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int omap3evm_panel_enable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 0);
+       return 0;
+}
+
+static void omap3evm_panel_disable(struct lcd_panel *panel)
+{
+       omap_set_gpio_dataout(LCD_PANEL_ENABLE_GPIO, 1);
+}
+
+static unsigned long omap3evm_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+static int omap3evm_bklight_setlevel(struct lcd_panel *panel,
+                                               unsigned int level)
+{
+       u8 c;
+       if ((level >= 0) && (level <= 100)) {
+               c = (125 * (100 - level)) / 100 + 2;
+               twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
+               bklight_level = level;
+       }
+       return 0;
+}
+
+static unsigned int omap3evm_bklight_getlevel(struct lcd_panel *panel)
+{
+       return bklight_level;
+}
+
+static unsigned int omap3evm_bklight_getmaxlevel(struct lcd_panel *panel)
+{
+       return 100;
+}
+
+struct lcd_panel omap3evm_panel = {
+       .name           = "omap3evm",
+       .config         = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+                         OMAP_LCDC_INV_HSYNC,
+
+       .bpp            = 16,
+       .data_lines     = 18,
+       .x_res          = LCD_XRES,
+       .y_res          = LCD_YRES,
+       .hsw            = 3,            /* hsync_len (4) - 1 */
+       .hfp            = 3,            /* right_margin (4) - 1 */
+       .hbp            = 39,           /* left_margin (40) - 1 */
+       .vsw            = 1,            /* vsync_len (2) - 1 */
+       .vfp            = 2,            /* lower_margin */
+       .vbp            = 7,            /* upper_margin (8) - 1 */
+
+       .pixel_clock    = LCD_PIXCLOCK,
+
+       .init           = omap3evm_panel_init,
+       .cleanup        = omap3evm_panel_cleanup,
+       .enable         = omap3evm_panel_enable,
+       .disable        = omap3evm_panel_disable,
+       .get_caps       = omap3evm_panel_get_caps,
+       .set_bklight_level      = omap3evm_bklight_setlevel,
+       .get_bklight_level      = omap3evm_bklight_getlevel,
+       .get_bklight_max        = omap3evm_bklight_getmaxlevel,
+};
+
+static int omap3evm_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&omap3evm_panel);
+       return 0;
+}
+
+static int omap3evm_panel_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static int omap3evm_panel_suspend(struct platform_device *pdev,
+                                  pm_message_t mesg)
+{
+       return 0;
+}
+
+static int omap3evm_panel_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+struct platform_driver omap3evm_panel_driver = {
+       .probe          = omap3evm_panel_probe,
+       .remove         = omap3evm_panel_remove,
+       .suspend        = omap3evm_panel_suspend,
+       .resume         = omap3evm_panel_resume,
+       .driver         = {
+               .name   = "omap3evm_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap3evm_panel_drv_init(void)
+{
+       return platform_driver_register(&omap3evm_panel_driver);
+}
+
+static void __exit omap3evm_panel_drv_exit(void)
+{
+       platform_driver_unregister(&omap3evm_panel_driver);
+}
+
+module_init(omap3evm_panel_drv_init);
+module_exit(omap3evm_panel_drv_exit);
index a4a725f427a487843b03cad5e45abbf4fd230004..379c96d36da5833377e5d5df97085662ed6b52f5 100644 (file)
@@ -29,6 +29,7 @@
 
 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
 {
+       /* gpio2 was allocated in board init */
        return 0;
 }
 
@@ -47,11 +48,8 @@ static int osk_panel_enable(struct lcd_panel *panel)
        /* 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);
+       /* set GPIO2 high (lcd power enabled) */
+       gpio_set_value(2, 1);
 
        return 0;
 }
@@ -65,7 +63,7 @@ static void osk_panel_disable(struct lcd_panel *panel)
        omap_writeb(0x00, OMAP_PWL_CLK_ENABLE);
 
        /* set GPIO2 low */
-       omap_set_gpio_dataout(2, 0);
+       gpio_set_value(2, 0);
 }
 
 static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
new file mode 100644 (file)
index 0000000..2bc5c92
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * LCD panel support for the Gumstix Overo
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+#include <mach/gpio.h>
+#include <mach/mux.h>
+#include <mach/omapfb.h>
+#include <asm/mach-types.h>
+
+#define LCD_ENABLE       144
+
+static int overo_panel_init(struct lcd_panel *panel,
+                               struct omapfb_device *fbdev)
+{
+       if ((gpio_request(LCD_ENABLE, "LCD_ENABLE") == 0) &&
+           (gpio_direction_output(LCD_ENABLE, 1) == 0))
+               gpio_export(LCD_ENABLE, 0);
+       else
+               printk(KERN_ERR "could not obtain gpio for LCD_ENABLE\n");
+
+       return 0;
+}
+
+static void overo_panel_cleanup(struct lcd_panel *panel)
+{
+       gpio_free(LCD_ENABLE);
+}
+
+static int overo_panel_enable(struct lcd_panel *panel)
+{
+       gpio_set_value(LCD_ENABLE, 1);
+       return 0;
+}
+
+static void overo_panel_disable(struct lcd_panel *panel)
+{
+       gpio_set_value(LCD_ENABLE, 0);
+}
+
+static unsigned long overo_panel_get_caps(struct lcd_panel *panel)
+{
+       return 0;
+}
+
+struct lcd_panel overo_panel = {
+       .name           = "overo",
+       .config         = OMAP_LCDC_PANEL_TFT,
+       .bpp            = 16,
+       .data_lines     = 24,
+
+#if defined CONFIG_FB_OMAP_031M3R
+
+       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
+       .x_res          = 640,
+       .y_res          = 480,
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+       .vfp            = 3,
+       .vsw            = 4,
+       .vbp            = 7,
+       .pixel_clock    = 23500,
+
+#elif defined CONFIG_FB_OMAP_048M3R
+
+       /* 800 x 600 @ 60 Hz  Reduced blanking VESA CVT 0.48M3-R */
+       .x_res          = 800,
+       .y_res          = 600,
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+       .vfp            = 3,
+       .vsw            = 4,
+       .vbp            = 11,
+       .pixel_clock    = 35500,
+
+#elif defined CONFIG_FB_OMAP_079M3R
+
+       /* 1024 x 768 @ 60 Hz  Reduced blanking VESA CVT 0.79M3-R */
+       .x_res          = 1024,
+       .y_res          = 768,
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+       .vfp            = 3,
+       .vsw            = 4,
+       .vbp            = 15,
+       .pixel_clock    = 56000,
+
+#elif defined CONFIG_FB_OMAP_092M9R
+
+       /* 1280 x 720 @ 60 Hz  Reduced blanking VESA CVT 0.92M9-R */
+       .x_res          = 1280,
+       .y_res          = 720,
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+       .vfp            = 3,
+       .vsw            = 5,
+       .vbp            = 13,
+       .pixel_clock    = 64000,
+
+#else
+
+       /* use 640 x 480 if no config option */
+       /* 640 x 480 @ 60 Hz  Reduced blanking VESA CVT 0.31M3-R */
+       .x_res          = 640,
+       .y_res          = 480,
+       .hfp            = 48,
+       .hsw            = 32,
+       .hbp            = 80,
+       .vfp            = 3,
+       .vsw            = 4,
+       .vbp            = 7,
+       .pixel_clock    = 23500,
+
+#endif
+
+       .init           = overo_panel_init,
+       .cleanup        = overo_panel_cleanup,
+       .enable         = overo_panel_enable,
+       .disable        = overo_panel_disable,
+       .get_caps       = overo_panel_get_caps,
+};
+
+static int overo_panel_probe(struct platform_device *pdev)
+{
+       omapfb_register_panel(&overo_panel);
+       return 0;
+}
+
+static int overo_panel_remove(struct platform_device *pdev)
+{
+       /* omapfb does not have unregister_panel */
+       return 0;
+}
+
+static struct platform_driver overo_panel_driver = {
+       .probe          = overo_panel_probe,
+       .remove         = overo_panel_remove,
+       .driver         = {
+               .name   = "overo_lcd",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init overo_panel_drv_init(void)
+{
+       return platform_driver_register(&overo_panel_driver);
+}
+
+static void __exit overo_panel_drv_exit(void)
+{
+       platform_driver_unregister(&overo_panel_driver);
+}
+
+module_init(overo_panel_drv_init);
+module_exit(overo_panel_drv_exit);
diff --git a/drivers/video/omap/lcd_p2.c b/drivers/video/omap/lcd_p2.c
new file mode 100644 (file)
index 0000000..8c66bf6
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * LCD panel support for the TI OMAP P2 board
+ *
+ * Authors:
+ *   jekyll <jekyll@mail.jekyll.idv.tw>
+ *   B Jp <lastjp_fr@yahoo.fr>
+ *   Brian Swetland <swetland@android.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <mach/mux.h>
+#include <mach/gpio.h>
+#include <mach/omapfb.h>
+
+/*
+ * File: epson-md-tft.h
+ *
+ * This file contains definitions for Epsons MD-TF LCD Module
+ *
+ * Copyright (C) 2004 MPC-Data Limited  (http://www.mpc-data.co.uk)
+ * Author: Dave Peverley <dpeverley at mpc-data.co.uk>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS  PROVIDED  ``AS  IS''  AND   ANY  EXPRESS  OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Please report all bugs and problems to the author.
+ *
+ */
+
+/* LCD uWire commands & params
+ * All values from Epson
+ */
+#define LCD_DISON 0xAF
+#define LCD_DISOFF 0xAE
+#define LCD_DISNOR 0xA6
+#define LCD_DISINV 0xA7
+#define LCD_DISCTL 0xCA
+#define LCD_GCP64 0xCB
+#define LCD_GCP16 0xCC
+#define LCD_GSSET 0xCD
+#define LCD_SLPIN 0x95
+#define LCD_SLPOUT 0x94
+#define LCD_SD_PSET 0x75
+#define LCD_MD_PSET 0x76
+#define LCD_SD_CSET 0x15
+#define LCD_MD_CSET 0x16
+#define LCD_DATCTL 0xBC
+#define LCD_RAMWR 0x5C
+#define LCD_RAMRD 0x5D
+#define LCD_PTLIN 0xA8
+#define LCD_PTLOUT 0xA9
+#define LCD_ASCSET 0xAA
+#define LCD_SCSTART 0xAB
+#define LCD_VOLCTL 0xC6
+#define LCD_NOP 0x25
+#define LCD_OSCISEL 0x7
+#define LCD_3500KSET 0xD1
+#define LCD_3500KEND 0xD2
+#define LCD_14MSET 0xD3
+#define LCD_14MEND 0xD4
+
+#define INIT_3500KSET 0x45
+#define INIT_14MSET 0x4B
+#define INIT_DATCTL 0x08 /* 6.6.6 bits for D-Sample */
+
+#define INIT_OSCISEL 0x05
+
+#define INIT_VOLCTL 0x77 /* Nominel "volume" */
+
+#define INIT_VOLCTL_Ton 0x98 /* Activate power-IC timer */
+#define INIT_GSSET 0x00
+
+const unsigned short INIT_DISCTL[11] =
+{
+       0xDE, 0x01, 0x64, 0x00, 0x1B, 0xF4, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned short INIT_GCP64[126] =
+{
+       0x3B,0x00,0x42,0x00,0x4A,0x00,0x51,0x00,
+       0x58,0x00,0x5F,0x00,0x66,0x00,0x6E,0x00,
+       0x75,0x00,0x7C,0x00,0x83,0x00,0x8A,0x00,
+       0x92,0x00,0x99,0x00,0xA0,0x00,0xA7,0x00,
+       0xAE,0x00,0xB6,0x00,0xBD,0x00,0xC4,0x00,
+       0xCB,0x00,0xD2,0x00,0xDA,0x00,0xE1,0x00,
+       0xE8,0x00,0xEF,0x00,0xF6,0x00,0xFE,0x00,
+       0x05,0x01,0x0C,0x01,0x13,0x01,0x1A,0x01,
+       0x22,0x01,0x29,0x01,0x30,0x01,0x37,0x01,
+       0x3E,0x01,0x46,0x01,0x4D,0x01,0x54,0x01,
+       0x5B,0x01,0x62,0x01,0x6A,0x01,0x71,0x01,
+       0x78,0x01,0x7F,0x01,0x86,0x01,0x8E,0x01,
+       0x95,0x01,0x9C,0x01,0xA3,0x01,0xAA,0x01,
+       0xB2,0x01,0xB9,0x01,0xC0,0x01,0xC7,0x01,
+       0xCE,0x01,0xD6,0x01,0xDD,0x01,0xE4,0x01,
+       0xEB,0x01,0xF2,0x01,0xFA,0x01
+};
+
+const unsigned short INIT_GCP16[15] =
+{
+       0x1A,0x31,0x48,0x54,0x5F,0x67,0x70,0x76,0x7C,0x80,0x83,0x84,0x85,0x87,0x96
+};
+
+const unsigned short INIT_MD_PSET[4] = { 0, 0, 219, 0 };
+const unsigned short INIT_MD_CSET[4] = { 2, 0, 177, 0 };
+
+const unsigned short INIT_SD_PSET[4] = { 0x00, 0x01, 0x00, 0x01 };
+const unsigned short INIT_SD_CSET[4] = { 0x00, 0x02, 0x00, 0x02 };
+
+const unsigned short INIT_ASCSET[7] = { 0x00, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0x01 };
+const unsigned short INIT_SCSTART[2] = { 0x00, 0x00 };
+
+/* ----- end of epson_md_tft.h ----- */
+
+
+#include "../drivers/ssi/omap-uwire.h"
+
+#define LCD_UWIRE_CS 0
+
+static int p2_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+       return 0;
+}
+
+static void p2_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int p2_panel_enable(struct lcd_panel *panel)
+{
+       int i;
+       unsigned long value;
+
+               /* thwack the reset line */
+       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);
+
index caa6a896cb8b7d84912dceb6a45b7e3871f3c588..e55de201b8ff4508e6de02ae29c970acf9cffb2f 100644 (file)
@@ -81,21 +81,21 @@ static void epson_sendbyte(int flag, unsigned char byte)
        int i, shifter = 0x80;
 
        if (!flag)
-               omap_set_gpio_dataout(_A_LCD_SSC_A0, 0);
+               gpio_set_value(_A_LCD_SSC_A0, 0);
        mdelay(2);
-       omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+       gpio_set_value(A_LCD_SSC_RD, 1);
 
-       omap_set_gpio_dataout(A_LCD_SSC_SD, flag);
+       gpio_set_value(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);
+               gpio_set_value(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);
+       gpio_set_value(_A_LCD_SSC_A0, 1);
 }
 
 static void init_system(void)
@@ -107,25 +107,18 @@ static void init_system(void)
 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);
+       gpio_request(A_LCD_SSC_RD, "lcd_ssc_rd");
+       gpio_request(A_LCD_SSC_SD, "lcd_ssc_sd");
+       gpio_request(_A_LCD_RESET, "lcd_reset");
+       gpio_request(_A_LCD_SSC_CS, "lcd_ssc_cs");
+       gpio_request(_A_LCD_SSC_A0, "lcd_ssc_a0");
+
+       /* set GPIOs to output, with initial data */
+       gpio_direction_output(A_LCD_SSC_RD, 1);
+       gpio_direction_output(A_LCD_SSC_SD, 0);
+       gpio_direction_output(_A_LCD_RESET, 0);
+       gpio_direction_output(_A_LCD_SSC_CS, 1);
+       gpio_direction_output(_A_LCD_SSC_A0, 1);
 }
 
 static void display_init(void)
@@ -139,61 +132,61 @@ static void display_init(void)
        mdelay(2);
 
        /* reset LCD */
-       omap_set_gpio_dataout(A_LCD_SSC_SD, 1);
+       gpio_set_value(A_LCD_SSC_SD, 1);
        epson_sendbyte(0, 0x25);
 
-       omap_set_gpio_dataout(_A_LCD_RESET, 0);
+       gpio_set_value(_A_LCD_RESET, 0);
        mdelay(10);
-       omap_set_gpio_dataout(_A_LCD_RESET, 1);
+       gpio_set_value(_A_LCD_RESET, 1);
 
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(2);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(100); /* used to be 1000 */
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 7 */
        epson_sendbyte(0, 0x16);
@@ -201,8 +194,8 @@ static void display_init(void)
        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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 8 */
        epson_sendbyte(0, 0x76);
@@ -210,12 +203,12 @@ static void display_init(void)
        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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        /* init LCD phase 9 */
        epson_sendbyte(0, 0xAF);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 }
 
 static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
@@ -231,18 +224,18 @@ 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);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 
        epson_sendbyte(0, 0x25);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        epson_sendbyte(0, 0xAE);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
        mdelay(100);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+       gpio_set_value(_A_LCD_SSC_CS, 0);
 
        epson_sendbyte(0, 0x95);
-       omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+       gpio_set_value(_A_LCD_SSC_CS, 1);
 }
 
 static int sx1_panel_enable(struct lcd_panel *panel)
index 83514f066712c4d3157b9c3c1c1b2a72d7b82d68..6e2ea7518761cb95b8161080d6adadc0ed2de792 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <asm/mach-types.h>
 
+#include "lcdc.h"
+
 #define MODULE_NAME                    "lcdc"
 
 #define OMAP_LCDC_BASE                 0xfffec000
index adb731e5314a22e5702e98f389e81c33614c78dd..845222270db3f60b01ffdd7278f0c15ac3be2ac1 100644 (file)
@@ -4,4 +4,6 @@
 int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
 void omap_lcdc_free_dma_callback(void);
 
+extern const struct lcd_ctrl omap1_int_ctrl;
+
 #endif
index 51a138bd113c0a42a4d385bf0af2ab4e8b790ab6..d176a2cf7aaf7c014b8597fb4593c7c014d6348d 100644 (file)
 #include <mach/dma.h>
 #include <mach/omapfb.h>
 
+#include "lcdc.h"
+#include "dispc.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 int    def_vram_cnt;
 static unsigned long   def_vxres;
 static unsigned long   def_vyres;
 static unsigned int    def_rotate;
@@ -64,6 +67,7 @@ static struct caps_table_struct ctrl_caps[] = {
        { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
        { OMAPFB_CAPS_WINDOW_SCALE,   "scale window" },
        { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
+       { OMAPFB_CAPS_WINDOW_ROTATE,  "rotate window" },
        { OMAPFB_CAPS_SET_BACKLIGHT,  "backlight setting" },
 };
 
@@ -84,12 +88,10 @@ static struct caps_table_struct color_caps[] = {
  * LCD panel
  * ---------------------------------------------------------------------------
  */
-extern struct lcd_ctrl omap1_int_ctrl;
-extern struct lcd_ctrl omap2_int_ctrl;
 extern struct lcd_ctrl hwa742_ctrl;
 extern struct lcd_ctrl blizzard_ctrl;
 
-static struct lcd_ctrl *ctrls[] = {
+static const struct lcd_ctrl *ctrls[] = {
 #ifdef CONFIG_ARCH_OMAP1
        &omap1_int_ctrl,
 #else
@@ -214,13 +216,22 @@ static int ctrl_change_mode(struct fb_info *fbi)
                                 offset, var->xres_virtual,
                                 plane->info.pos_x, plane->info.pos_y,
                                 var->xres, var->yres, plane->color_mode);
-       if (fbdev->ctrl->set_scale != NULL)
+       if (r < 0)
+               return r;
+
+       if (fbdev->ctrl->set_rotate != NULL)
+               if((r = fbdev->ctrl->set_rotate(var->rotate)) < 0)
+                       return r;
+
+       if ((fbdev->ctrl->set_scale != NULL) && (plane->idx > 0))
                r = fbdev->ctrl->set_scale(plane->idx,
                                   var->xres, var->yres,
                                   plane->info.out_width,
                                   plane->info.out_height);
+       if (r < 0)
+               return r;
 
-       return r;
+       return 0;
 }
 
 /*
@@ -551,7 +562,6 @@ static int set_fb_var(struct fb_info *fbi,
                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;
@@ -597,7 +607,7 @@ static void omapfb_rotate(struct fb_info *fbi, int rotate)
        struct omapfb_device *fbdev = plane->fbdev;
 
        omapfb_rqueue_lock(fbdev);
-       if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
+       if (rotate != fbi->var.rotate) {
                struct fb_var_screeninfo *new_var = &fbdev->new_var;
 
                memcpy(new_var, &fbi->var, sizeof(*new_var));
@@ -704,28 +714,42 @@ int omapfb_update_window_async(struct fb_info *fbi,
                                void (*callback)(void *),
                                void *callback_data)
 {
+       int xres, yres;
        struct omapfb_plane_struct *plane = fbi->par;
        struct omapfb_device *fbdev = plane->fbdev;
-       struct fb_var_screeninfo *var;
+       struct fb_var_screeninfo *var = &fbi->var;
 
-       var = &fbi->var;
-       if (win->x >= var->xres || win->y >= var->yres ||
-           win->out_x > var->xres || win->out_y >= var->yres)
+       switch (var->rotate) {
+       case 0:
+       case 180:
+               xres = fbdev->panel->x_res;
+               yres = fbdev->panel->y_res;
+               break;
+       case 90:
+       case 270:
+               xres = fbdev->panel->y_res;
+               yres = fbdev->panel->x_res;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (win->x >= xres || win->y >= yres ||
+           win->out_x > xres || win->out_y > yres)
                return -EINVAL;
 
        if (!fbdev->ctrl->update_window ||
            fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
                return -ENODEV;
 
-       if (win->x + win->width >= var->xres)
-               win->width = var->xres - win->x;
-       if (win->y + win->height >= var->yres)
-               win->height = var->yres - win->y;
-       /* The out sizes should be cropped to the LCD size */
-       if (win->out_x + win->out_width > fbdev->panel->x_res)
-               win->out_width = fbdev->panel->x_res - win->out_x;
-       if (win->out_y + win->out_height > fbdev->panel->y_res)
-               win->out_height = fbdev->panel->y_res - win->out_y;
+       if (win->x + win->width > xres)
+               win->width = xres - win->x;
+       if (win->y + win->height > yres)
+               win->height = yres - win->y;
+       if (win->out_x + win->out_width > xres)
+               win->out_width = xres - win->out_x;
+       if (win->out_y + win->out_height > yres)
+               win->out_height = yres - win->out_y;
        if (!win->width || !win->height || !win->out_width || !win->out_height)
                return 0;
 
@@ -740,7 +764,7 @@ static int omapfb_update_win(struct fb_info *fbi,
        int ret;
 
        omapfb_rqueue_lock(plane->fbdev);
-       ret = omapfb_update_window_async(fbi, win, NULL, 0);
+       ret = omapfb_update_window_async(fbi, win, NULL, NULL);
        omapfb_rqueue_unlock(plane->fbdev);
 
        return ret;
@@ -768,7 +792,7 @@ static int omapfb_update_full_screen(struct fb_info *fbi)
        win.format = 0;
 
        omapfb_rqueue_lock(fbdev);
-       r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
+       r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL);
        omapfb_rqueue_unlock(fbdev);
 
        return r;
@@ -1047,7 +1071,7 @@ void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
                win.height = 2;
                win.out_width = 2;
                win.out_height = 2;
-               fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
+               fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL);
        }
        omapfb_rqueue_unlock(fbdev);
 }
@@ -1817,8 +1841,8 @@ 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]);
-
+       if (fbdev != NULL)
+               omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
        return 0;
 }
 
@@ -1827,7 +1851,8 @@ 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]);
+       if (fbdev != NULL)
+               omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
        return 0;
 }
 
index 4a6f13d3facf9d69ed984036d599248f5dfd328e..c57b1b9b28b9245645ca0e33f5bf0c439c28ba5a 100644 (file)
@@ -2,7 +2,7 @@
  * OMAP2 Remote Frame Buffer Interface support
  *
  * Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrj�l� <juha.yrjola@nokia.com>
  *        Imre Deak <imre.deak@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
 #define DISPC_CONTROL          0x0040
 
 static struct {
-       u32             base;
+       void __iomem    *base;
        void            (*lcdc_callback)(void *data);
        void            *lcdc_callback_data;
        unsigned long   l4_khz;
@@ -518,7 +518,11 @@ static int rfbi_init(struct omapfb_device *fbdev)
        int r;
 
        rfbi.fbdev = fbdev;
-       rfbi.base = io_p2v(RFBI_BASE);
+       rfbi.base = ioremap(RFBI_BASE, SZ_1K);
+       if (!rfbi.base) {
+               dev_err(fbdev->dev, "can't ioremap RFBI\n");
+               return -ENOMEM;
+       }
 
        if ((r = rfbi_get_clocks()) < 0)
                return r;
@@ -566,6 +570,7 @@ static void rfbi_cleanup(void)
 {
        omap_dispc_free_irq();
        rfbi_put_clocks();
+       iounmap(rfbi.base);
 }
 
 const struct lcd_ctrl_extif omap2_ext_if = {
index 6359353c2c67feb92f0d004d2f93fbb1cce35e38..cc697ccd82953bdcdaa83ff287a96ef0dc9e685c 100644 (file)
@@ -2,7 +2,7 @@
  * OMAP1 Special OptimiSed Screen Interface support
  *
  * Copyright (C) 2004-2005 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrj�l� <juha.yrjola@nokia.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -574,7 +574,12 @@ static int sossi_init(struct omapfb_device *fbdev)
        struct clk *dpll1out_ck;
        int r;
 
-       sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
+       sossi.base = ioremap(OMAP_SOSSI_BASE, SZ_1K);
+       if (!sossi.base) {
+               dev_err(fbdev->dev, "can't ioremap SoSSI\n");
+               return -ENOMEM;
+       }
+
        sossi.fbdev = fbdev;
        spin_lock_init(&sossi.lock);
 
@@ -665,6 +670,7 @@ static void sossi_cleanup(void)
 {
        omap_lcdc_free_dma_callback();
        clk_put(sossi.fck);
+       iounmap(sossi.base);
 }
 
 struct lcd_ctrl_extif omap1_ext_if = {
index c4493091c655d109dd008983183048b02c2a304e..636d4f767ea221e7dc5db4118d647d78276a0433 100644 (file)
@@ -42,6 +42,13 @@ config W1_MASTER_DS1WM
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
          hx4700.
 
+config HDQ_MASTER_OMAP
+       tristate "OMAP HDQ driver"
+       depends on ARCH_OMAP2430 || ARCH_OMAP34XX
+       help
+         Say Y here if you want support for the 1-wire or HDQ Interface
+         on an OMAP processor.
+
 config W1_MASTER_GPIO
        tristate "GPIO 1-wire busmaster"
        depends on GENERIC_GPIO
index 1420b5bbdda81f930379dfac9e776af216af7557..1daeb6e4b956a181eb797682b0b3986841545e18 100644 (file)
@@ -6,4 +6,5 @@ obj-$(CONFIG_W1_MASTER_MATROX)          += matrox_w1.o
 obj-$(CONFIG_W1_MASTER_DS2490)         += ds2490.o
 obj-$(CONFIG_W1_MASTER_DS2482)         += ds2482.o
 obj-$(CONFIG_W1_MASTER_DS1WM)          += ds1wm.o
+obj-$(CONFIG_HDQ_MASTER_OMAP)          += omap_hdq.o
 obj-$(CONFIG_W1_MASTER_GPIO)           += w1-gpio.o
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
new file mode 100644 (file)
index 0000000..e7fa6ab
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * drivers/w1/masters/omap_hdq.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+#define        MOD_NAME        "OMAP_HDQ:"
+
+#define OMAP_HDQ_REVISION                      0x00
+#define OMAP_HDQ_TX_DATA                       0x04
+#define OMAP_HDQ_RX_DATA                       0x08
+#define OMAP_HDQ_CTRL_STATUS                   0x0c
+#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK     (1<<6)
+#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE       (1<<5)
+#define OMAP_HDQ_CTRL_STATUS_GO                        (1<<4)
+#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION    (1<<2)
+#define OMAP_HDQ_CTRL_STATUS_DIR               (1<<1)
+#define OMAP_HDQ_CTRL_STATUS_MODE              (1<<0)
+#define OMAP_HDQ_INT_STATUS                    0x10
+#define OMAP_HDQ_INT_STATUS_TXCOMPLETE         (1<<2)
+#define OMAP_HDQ_INT_STATUS_RXCOMPLETE         (1<<1)
+#define OMAP_HDQ_INT_STATUS_TIMEOUT            (1<<0)
+#define OMAP_HDQ_SYSCONFIG                     0x14
+#define OMAP_HDQ_SYSCONFIG_SOFTRESET           (1<<1)
+#define OMAP_HDQ_SYSCONFIG_AUTOIDLE            (1<<0)
+#define OMAP_HDQ_SYSSTATUS                     0x18
+#define OMAP_HDQ_SYSSTATUS_RESETDONE           (1<<0)
+
+#define OMAP_HDQ_FLAG_CLEAR                    0
+#define OMAP_HDQ_FLAG_SET                      1
+#define OMAP_HDQ_TIMEOUT                       (HZ/5)
+
+#define OMAP_HDQ_MAX_USER                      4
+
+static DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
+static int w1_id;
+
+struct hdq_data {
+       struct device           *dev;
+       void __iomem            *hdq_base;
+       /* lock status update */
+       struct  mutex           hdq_mutex;
+       int                     hdq_usecount;
+       struct  clk             *hdq_ick;
+       struct  clk             *hdq_fck;
+       u8                      hdq_irqstatus;
+       /* device lock */
+       spinlock_t              hdq_spinlock;
+       /*
+        * Used to control the call to omap_hdq_get and omap_hdq_put.
+        * HDQ Protocol: Write the CMD|REG_address first, followed by
+        * the data wrire or read.
+        */
+       int                     init_trans;
+};
+
+static int omap_hdq_get(struct hdq_data *hdq_data);
+static int omap_hdq_put(struct hdq_data *hdq_data);
+static int omap_hdq_break(struct hdq_data *hdq_data);
+
+static int __init omap_hdq_probe(struct platform_device *pdev);
+static int omap_hdq_remove(struct platform_device *pdev);
+
+static struct platform_driver omap_hdq_driver = {
+       .probe =        omap_hdq_probe,
+       .remove =       omap_hdq_remove,
+       .driver =       {
+               .name = "omap_hdq",
+       },
+};
+
+static u8 omap_w1_read_byte(void *_hdq);
+static void omap_w1_write_byte(void *_hdq, u8 byte);
+static u8 omap_w1_reset_bus(void *_hdq);
+static void omap_w1_search_bus(void *_hdq, u8 search_type,
+       w1_slave_found_callback slave_found);
+
+
+static struct w1_bus_master omap_w1_master = {
+       .read_byte      = omap_w1_read_byte,
+       .write_byte     = omap_w1_write_byte,
+       .reset_bus      = omap_w1_reset_bus,
+       .search         = omap_w1_search_bus,
+};
+
+/* HDQ register I/O routines */
+static inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
+{
+       return __raw_readb(hdq_data->hdq_base + offset);
+}
+
+static inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
+{
+       __raw_writeb(val, hdq_data->hdq_base + offset);
+}
+
+static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
+                       u8 val, u8 mask)
+{
+       u8 new_val = (__raw_readb(hdq_data->hdq_base + offset) & ~mask)
+                       | (val & mask);
+       __raw_writeb(new_val, hdq_data->hdq_base + offset);
+
+       return new_val;
+}
+
+/*
+ * Wait for one or more bits in flag change.
+ * HDQ_FLAG_SET: wait until any bit in the flag is set.
+ * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
+ * return 0 on success and -ETIMEDOUT in the case of timeout.
+ */
+static int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
+               u8 flag, u8 flag_set, u8 *status)
+{
+       int ret = 0;
+       unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+       if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
+               /* wait for the flag clear */
+               while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
+                       && time_before(jiffies, timeout)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(1);
+               }
+               if (*status & flag)
+                       ret = -ETIMEDOUT;
+       } else if (flag_set == OMAP_HDQ_FLAG_SET) {
+               /* wait for the flag set */
+               while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
+                       && time_before(jiffies, timeout)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(1);
+               }
+               if (!(*status & flag))
+                       ret = -ETIMEDOUT;
+       } else
+               return -EINVAL;
+
+       return ret;
+}
+
+/* write out a byte and fill *status with HDQ_INT_STATUS */
+static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
+{
+       int ret;
+       u8 tmp_status;
+       unsigned long irqflags;
+
+       *status = 0;
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       /* clear interrupt flags via a dummy read */
+       hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       /* ISR loads it with new INT_STATUS */
+       hdq_data->hdq_irqstatus = 0;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+       hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
+
+       /* set the GO bit */
+       hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
+               OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+       /* wait for the TXCOMPLETE bit */
+       ret = wait_event_interruptible_timeout(hdq_wait_queue,
+               hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+       if (ret < 0) {
+               dev_dbg(hdq_data->dev, "wait interrupted");
+               return -EINTR;
+       }
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       *status = hdq_data->hdq_irqstatus;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+       /* check irqstatus */
+       if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
+               dev_dbg(hdq_data->dev, "timeout waiting for"
+                       "TXCOMPLETE/RXCOMPLETE, %x", *status);
+               return -ETIMEDOUT;
+       }
+
+       /* wait for the GO bit return to zero */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_GO,
+                       OMAP_HDQ_FLAG_CLEAR, &tmp_status);
+       if (ret) {
+               dev_dbg(hdq_data->dev, "timeout waiting GO bit"
+                       "return to zero, %x", tmp_status);
+               return ret;
+       }
+
+       return ret;
+}
+
+/* HDQ Interrupt service routine */
+static irqreturn_t hdq_isr(int irq, void *_hdq)
+{
+       struct hdq_data *hdq_data = _hdq;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+       dev_dbg(hdq_data->dev, "hdq_isr: %x", hdq_data->hdq_irqstatus);
+
+       if (hdq_data->hdq_irqstatus &
+               (OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
+               | OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+               /* wake up sleeping process */
+               wake_up_interruptible(&hdq_wait_queue);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* HDQ Mode: always return success */
+static u8 omap_w1_reset_bus(void *_hdq)
+{
+       return 0;
+}
+
+/* W1 search callback function */
+static void omap_w1_search_bus(void *_hdq, u8 search_type,
+       w1_slave_found_callback slave_found)
+{
+       u64 module_id, rn_le, cs, id;
+
+       if (w1_id)
+               module_id = w1_id;
+       else
+               module_id = 0x1;
+
+       rn_le = cpu_to_le64(module_id);
+       /*
+        * HDQ might not obey truly the 1-wire spec.
+        * So calculate CRC based on module parameter.
+        */
+       cs = w1_calc_crc8((u8 *)&rn_le, 7);
+       id = (cs << 56) | module_id;
+
+       slave_found(_hdq, id);
+}
+
+static int _omap_hdq_reset(struct hdq_data *hdq_data)
+{
+       int ret;
+       u8 tmp_status;
+
+       hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_SOFTRESET);
+       /*
+        * Select HDQ mode & enable clocks.
+        * It is observed that INT flags can't be cleared via a read and GO/INIT
+        * won't return to zero if interrupt is disabled. So we always enable
+        * interrupt.
+        */
+       hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+               OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+               OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+
+       /* wait for reset to complete */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
+               OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status);
+       if (ret)
+               dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x",
+                               tmp_status);
+       else {
+               hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+                       OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+               hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+                       OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+       }
+
+       return ret;
+}
+
+/* Issue break pulse to the device */
+static int omap_hdq_break(struct hdq_data *hdq_data)
+{
+       int ret;
+       u8 tmp_status;
+       unsigned long irqflags;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0)
+               return -EINTR;
+
+       if (!hdq_data->hdq_usecount) {
+               mutex_unlock(&hdq_data->hdq_mutex);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       /* clear interrupt flags via a dummy read */
+       hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+       /* ISR loads it with new INT_STATUS */
+       hdq_data->hdq_irqstatus = 0;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+
+       /* set the INIT and GO bit */
+       hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+               OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
+               OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+               OMAP_HDQ_CTRL_STATUS_GO);
+
+       /* wait for the TIMEOUT bit */
+       ret = wait_event_interruptible_timeout(hdq_wait_queue,
+               hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT);
+       if (ret < 0) {
+               dev_dbg(hdq_data->dev, "wait interrupted");
+               mutex_unlock(&hdq_data->hdq_mutex);
+               return -EINTR;
+       }
+
+       spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+       tmp_status = hdq_data->hdq_irqstatus;
+       spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+       /* check irqstatus */
+       if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
+               dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x",
+                               tmp_status);
+               mutex_unlock(&hdq_data->hdq_mutex);
+               return -ETIMEDOUT;
+       }
+       /*
+        * wait for both INIT and GO bits rerurn to zero.
+        * zero wait time expected for interrupt mode.
+        */
+       ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
+                       OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
+                       &tmp_status);
+       if (ret)
+               dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
+                       "return to zero, %x", tmp_status);
+
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       return ret;
+}
+
+static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
+{
+       int ret;
+       u8 status;
+       unsigned long irqflags;
+       unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0)
+               return -EINTR;
+
+       if (!hdq_data->hdq_usecount) {
+               mutex_unlock(&hdq_data->hdq_mutex);
+               return -EINVAL;
+       }
+
+       if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+               hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                       OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
+                       OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
+               /*
+                * The RX comes immediately after TX. It
+                * triggers another interrupt before we
+                * sleep. So we have to wait for RXCOMPLETE bit.
+                */
+               while (!(hdq_data->hdq_irqstatus
+                       & OMAP_HDQ_INT_STATUS_RXCOMPLETE)
+                       && time_before(jiffies, timeout)) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       schedule_timeout(1);
+               }
+               hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
+                       OMAP_HDQ_CTRL_STATUS_DIR);
+               spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
+               status = hdq_data->hdq_irqstatus;
+               spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
+               /* check irqstatus */
+               if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
+                       dev_dbg(hdq_data->dev, "timeout waiting for"
+                               "RXCOMPLETE, %x", status);
+                       mutex_unlock(&hdq_data->hdq_mutex);
+                       return -ETIMEDOUT;
+               }
+       }
+       /* the data is ready. Read it in! */
+       *val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       return 0;
+
+}
+
+/* Enable clocks and set the controller to HDQ mode */
+static int omap_hdq_get(struct hdq_data *hdq_data)
+{
+       int ret = 0;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0)
+               return -EINTR;
+
+       if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) {
+               dev_dbg(hdq_data->dev, "attempt to exceed the max use count");
+               mutex_unlock(&hdq_data->hdq_mutex);
+               ret = -EINVAL;
+       } else {
+               hdq_data->hdq_usecount++;
+               try_module_get(THIS_MODULE);
+               if (1 == hdq_data->hdq_usecount) {
+                       if (clk_enable(hdq_data->hdq_ick)) {
+                               dev_dbg(hdq_data->dev, "Can not enable ick\n");
+                               clk_put(hdq_data->hdq_ick);
+                               clk_put(hdq_data->hdq_fck);
+                               mutex_unlock(&hdq_data->hdq_mutex);
+                               return -ENODEV;
+                       }
+                       if (clk_enable(hdq_data->hdq_fck)) {
+                               dev_dbg(hdq_data->dev, "Can not enable fck\n");
+                               clk_put(hdq_data->hdq_ick);
+                               clk_put(hdq_data->hdq_fck);
+                               mutex_unlock(&hdq_data->hdq_mutex);
+                               return -ENODEV;
+                       }
+
+                       /* make sure HDQ is out of reset */
+                       if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) &
+                               OMAP_HDQ_SYSSTATUS_RESETDONE)) {
+                               ret = _omap_hdq_reset(hdq_data);
+                               if (ret)
+                                       /* back up the count */
+                                       hdq_data->hdq_usecount--;
+                       } else {
+                               /* select HDQ mode & enable clocks */
+                               hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
+                                       OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
+                                       OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK);
+                               hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG,
+                                       OMAP_HDQ_SYSCONFIG_AUTOIDLE);
+                               hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
+                       }
+               }
+       }
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       return ret;
+}
+
+/* Disable clocks to the module */
+static int omap_hdq_put(struct hdq_data *hdq_data)
+{
+       int ret = 0;
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0)
+               return -EINTR;
+
+       if (0 == hdq_data->hdq_usecount) {
+               dev_dbg(hdq_data->dev, "attempt to decrement use count"
+                       "when it is zero");
+               ret = -EINVAL;
+       } else {
+               hdq_data->hdq_usecount--;
+               module_put(THIS_MODULE);
+               if (0 == hdq_data->hdq_usecount) {
+                       clk_disable(hdq_data->hdq_ick);
+                       clk_disable(hdq_data->hdq_fck);
+               }
+       }
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       return ret;
+}
+
+/* Read a byte of data from the device */
+static u8 omap_w1_read_byte(void *_hdq)
+{
+       struct hdq_data *hdq_data = _hdq;
+       u8 val;
+       int ret;
+
+       ret = hdq_read_byte(hdq_data, &val);
+       if (ret) {
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return -EINTR;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+               omap_hdq_put(hdq_data);
+               return -1;
+       }
+
+       /* Write followed by a read, release the module */
+       if (hdq_data->init_trans) {
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return -EINTR;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+               omap_hdq_put(hdq_data);
+       }
+
+       return val;
+}
+
+/* Write a byte of data to the device */
+static void omap_w1_write_byte(void *_hdq, u8 byte)
+{
+       struct hdq_data *hdq_data = _hdq;
+       int ret;
+       u8 status;
+
+       /* First write to initialize the transfer */
+       if (hdq_data->init_trans == 0)
+               omap_hdq_get(hdq_data);
+
+       ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+       if (ret < 0) {
+               dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+               return;
+       }
+       hdq_data->init_trans++;
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       hdq_write_byte(hdq_data, byte, &status);
+       dev_dbg(hdq_data->dev, "Ctrl status %x\n", status);
+
+       /* Second write, data transfered. Release the module */
+       if (hdq_data->init_trans > 1) {
+               omap_hdq_put(hdq_data);
+               ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
+               if (ret < 0) {
+                       dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
+                       return;
+               }
+               hdq_data->init_trans = 0;
+               mutex_unlock(&hdq_data->hdq_mutex);
+       }
+
+       return;
+}
+
+static int __init omap_hdq_probe(struct platform_device *pdev)
+{
+       struct hdq_data *hdq_data;
+       struct resource *res;
+       int ret, irq;
+       u8 rev;
+
+       if (!pdev)
+               return -ENODEV;
+
+       hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
+       if (!hdq_data) {
+               dev_dbg(&pdev->dev, "unable to allocate memory\n");
+               ret = -ENODEV;
+               goto err_kmalloc;
+       }
+
+       hdq_data->dev = &pdev->dev;
+       platform_set_drvdata(pdev, hdq_data);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_dbg(&pdev->dev, "unable to get resource\n");
+               ret = ENXIO;
+               goto err_resource;
+       }
+
+       hdq_data->hdq_base = ioremap(res->start, SZ_4K);
+       if (!hdq_data->hdq_base) {
+               dev_dbg(&pdev->dev, "ioremap failed\n");
+               ret = -EINVAL;
+               goto err_ioremap;
+       }
+
+       /* get interface & functional clock objects */
+       hdq_data->hdq_ick = clk_get(&pdev->dev, "hdq_ick");
+       hdq_data->hdq_fck = clk_get(&pdev->dev, "hdq_fck");
+
+       if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can't get HDQ clock objects\n");
+               if (IS_ERR(hdq_data->hdq_ick)) {
+                       ret = PTR_ERR(hdq_data->hdq_ick);
+                       goto err_clk;
+               }
+               if (IS_ERR(hdq_data->hdq_fck)) {
+                       ret = PTR_ERR(hdq_data->hdq_fck);
+                       clk_put(hdq_data->hdq_ick);
+                       goto err_clk;
+               }
+       }
+
+       hdq_data->hdq_usecount = 0;
+       mutex_init(&hdq_data->hdq_mutex);
+
+       if (clk_enable(hdq_data->hdq_ick)) {
+               dev_dbg(&pdev->dev, "Can not enable ick\n");
+               ret = -ENODEV;
+               goto err_ick;
+       }
+
+       if (clk_enable(hdq_data->hdq_fck)) {
+               dev_dbg(&pdev->dev, "Can not enable fck\n");
+               ret = -ENODEV;
+               goto err_fck;
+       }
+
+       rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
+       dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
+               (rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
+
+       spin_lock_init(&hdq_data->hdq_spinlock);
+       omap_hdq_break(hdq_data);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = -ENXIO;
+               goto err_irq;
+       }
+
+       ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data);
+       if (ret < 0) {
+               dev_dbg(&pdev->dev, "could not request irq\n");
+               goto err_irq;
+       }
+
+       /* don't clock the HDQ until it is needed */
+       clk_disable(hdq_data->hdq_ick);
+       clk_disable(hdq_data->hdq_fck);
+
+       omap_w1_master.data = hdq_data;
+
+       ret = w1_add_master_device(&omap_w1_master);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Failure in registering w1 master\n");
+               goto err_w1;
+       }
+
+       return 0;
+
+err_w1:
+err_irq:
+       clk_disable(hdq_data->hdq_fck);
+
+err_fck:
+       clk_disable(hdq_data->hdq_ick);
+
+err_ick:
+       clk_put(hdq_data->hdq_ick);
+       clk_put(hdq_data->hdq_fck);
+
+err_clk:
+       iounmap(hdq_data->hdq_base);
+
+err_ioremap:
+err_resource:
+       platform_set_drvdata(pdev, NULL);
+       kfree(hdq_data);
+
+err_kmalloc:
+       return ret;
+
+}
+
+static int omap_hdq_remove(struct platform_device *pdev)
+{
+       struct hdq_data *hdq_data = platform_get_drvdata(pdev);
+
+       mutex_lock(&hdq_data->hdq_mutex);
+
+       if (0 != hdq_data->hdq_usecount) {
+               dev_dbg(&pdev->dev, "removed when use count is not zero\n");
+               return -EBUSY;
+       }
+
+       mutex_unlock(&hdq_data->hdq_mutex);
+
+       /* remove module dependency */
+       clk_put(hdq_data->hdq_ick);
+       clk_put(hdq_data->hdq_fck);
+       free_irq(INT_24XX_HDQ_IRQ, hdq_data);
+       platform_set_drvdata(pdev, NULL);
+       iounmap(hdq_data->hdq_base);
+       kfree(hdq_data);
+
+       return 0;
+}
+
+static int __init
+omap_hdq_init(void)
+{
+       return platform_driver_register(&omap_hdq_driver);
+}
+module_init(omap_hdq_init);
+
+static void __exit
+omap_hdq_exit(void)
+{
+       platform_driver_unregister(&omap_hdq_driver);
+}
+module_exit(omap_hdq_exit);
+
+module_param(w1_id, int, S_IRUSR);
+MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("HDQ driver Library");
+MODULE_LICENSE("GPL");
index 3df29a122f84c559d6ca1dcc104725028f18a9a7..8960fe44059a4df157080a0c5f624febe353de20 100644 (file)
@@ -44,4 +44,12 @@ config W1_SLAVE_DS2760
 
          If you are unsure, say N.
 
+config W1_SLAVE_BQ27000
+       tristate "BQ27000 slave support"
+       depends on W1
+       help
+         Say Y here if you want to use a hdq
+         bq27000 slave support.
+
+
 endmenu
index a8eb7524df1db2c0c4db0dbe8a4097d9f65fcff6..990f400b6d22dc82563a382f6c0b7defd09820a6 100644 (file)
@@ -6,4 +6,4 @@ obj-$(CONFIG_W1_SLAVE_THERM)    += w1_therm.o
 obj-$(CONFIG_W1_SLAVE_SMEM)    += w1_smem.o
 obj-$(CONFIG_W1_SLAVE_DS2433)  += w1_ds2433.o
 obj-$(CONFIG_W1_SLAVE_DS2760)  += w1_ds2760.o
-
+obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c
new file mode 100644 (file)
index 0000000..0e8a3f3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * drivers/w1/slaves/w1_bq27000.c
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define HDQ_CMD_READ   (0)
+#define HDQ_CMD_WRITE  (1<<7)
+
+int F_ID;
+int family_id;
+
+void w1_bq27000_write(struct device *dev, u8 buf, u8 reg)
+{
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       if (!dev) {
+               pr_info("Could not obtain slave dev ptr\n");
+               return;
+       }
+
+       w1_write_8(sl->master, HDQ_CMD_WRITE | reg);
+       w1_write_8(sl->master, buf);
+}
+EXPORT_SYMBOL(w1_bq27000_write);
+
+int w1_bq27000_read(struct device *dev, u8 reg)
+{
+       u8 val;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       if (!dev)
+               return 0;
+
+       w1_write_8(sl->master, HDQ_CMD_READ | reg);
+       val = w1_read_8(sl->master);
+
+       return val;
+}
+EXPORT_SYMBOL(w1_bq27000_read);
+
+static int w1_bq27000_add_slave(struct w1_slave *sl)
+{
+       int ret;
+       int id = 1;
+       struct platform_device *pdev;
+
+       pdev = platform_device_alloc("bq27000-battery", id);
+       if (!pdev) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       pdev->dev.parent = &sl->dev;
+
+       ret = platform_device_add(pdev);
+       if (ret)
+               goto pdev_add_failed;
+
+       dev_set_drvdata(&sl->dev, pdev);
+
+       goto success;
+
+pdev_add_failed:
+       platform_device_unregister(pdev);
+success:
+       return ret;
+}
+
+static void w1_bq27000_remove_slave(struct w1_slave *sl)
+{
+       struct platform_device *pdev = dev_get_drvdata(&sl->dev);
+       platform_device_unregister(pdev);
+}
+
+static struct w1_family_ops w1_bq27000_fops = {
+       .add_slave      = w1_bq27000_add_slave,
+       .remove_slave   = w1_bq27000_remove_slave,
+};
+
+static struct w1_family w1_bq27000_family = {
+       .fid = 1,
+       .fops = &w1_bq27000_fops,
+};
+
+static int __init w1_bq27000_init(void)
+{
+       if (F_ID)
+               w1_bq27000_family.fid = F_ID;
+
+       return w1_register_family(&w1_bq27000_family);
+}
+
+static void __exit w1_bq27000_exit(void)
+{
+       w1_unregister_family(&w1_bq27000_family);
+}
+
+
+module_init(w1_bq27000_init);
+module_exit(w1_bq27000_exit);
+
+module_param(F_ID, int, S_IRUSR);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Ltd");
+MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip");
index f1df5343f4ad4a25ab87f7c1782216f1135eec33..b8189e8f2a5eac43591b988b636252e8935687c6 100644 (file)
@@ -189,6 +189,7 @@ struct w1_master *w1_search_master_id(u32 id);
 
 u8 w1_triplet(struct w1_master *dev, int bdir);
 void w1_write_8(struct w1_master *, u8);
+u8 w1_read_8(struct w1_master *);
 int w1_reset_bus(struct w1_master *);
 u8 w1_calc_crc8(u8 *, int);
 void w1_write_block(struct w1_master *, const u8 *, int);
index 30b6fbf83bd4a9fcead97864e679d6c7bd222d07..da08537ba8a0d0797cc4bc6f09f277b8b726c9b8 100644 (file)
@@ -177,7 +177,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir)
  * @param dev     the master device
  * @return        the byte read
  */
-static u8 w1_read_8(struct w1_master * dev)
+u8 w1_read_8(struct w1_master *dev)
 {
        int i;
        u8 res = 0;
@@ -190,6 +190,7 @@ static u8 w1_read_8(struct w1_master * dev)
 
        return res;
 }
+EXPORT_SYMBOL_GPL(w1_read_8);
 
 /**
  * Writes a series of bytes.
index c510367167009a1e57e88826bf6bbfb453357b9b..b02d0cd9b1c85f41cc7665bca92e35ae462a4c9b 100644 (file)
@@ -173,10 +173,10 @@ config EP93XX_WATCHDOG
 
 config OMAP_WATCHDOG
        tristate "OMAP Watchdog"
-       depends on ARCH_OMAP16XX || ARCH_OMAP24XX
+       depends on ARCH_OMAP16XX || ARCH_OMAP24XX || ARCH_OMAP34XX
        help
-         Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog.  Say 'Y' here to
-         enable the OMAP1610/OMAP1710 watchdog timer.
+         Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog.  Say 'Y'
+         here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
 
 config PNX4008_WATCHDOG
        tristate "PNX4008 Watchdog"
index 3a11dadfd8e7dba34103f9d9b8685648e14a6f31..7bcbb7f4745f622758d68e2b36188d94c0668da8 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
  *
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
  *
  * Author: MontaVista Software, Inc.
  *      <gdavis@mvista.com> or <source@mvista.com>
 
 #include "omap_wdt.h"
 
+static struct platform_device *omap_wdt_dev;
+
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
 static unsigned int wdt_trgr_pattern = 0x1234;
 static spinlock_t wdt_lock;
 
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+       void __iomem    *base;          /* physical */
+       struct device   *dev;
+       int             omap_wdt_users;
+       struct clk      *armwdt_ck;
+       struct clk      *mpu_wdt_ick;
+       struct clk      *mpu_wdt_fck;
+       struct resource *mem;
+       struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
 {
+       void __iomem    *base = wdev->base;
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
+
        wdt_trgr_pattern = ~wdt_trgr_pattern;
-       omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        /* reloaded WCRR from WLDR */
 }
 
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* Sequence to enable the watchdog */
-       omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+       __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
-       omap_writel(0x4444, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+       __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 }
 
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* sequence required to disable watchdog */
-       omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+       __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
-       omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+       __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 }
 
@@ -103,83 +121,90 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
        timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
        u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
-       omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+       __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 }
 
 /*
  *     Allow only one task to hold it open
  */
-
 static int omap_wdt_open(struct inode *inode, struct file *file)
 {
-       if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       void __iomem *base = wdev->base;
+
+       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
                return -EBUSY;
 
        if (cpu_is_omap16xx())
-               clk_enable(armwdt_ck);  /* Enable the clock */
+               clk_enable(wdev->armwdt_ck);    /* Enable the clock */
 
-       if (cpu_is_omap24xx()) {
-               clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
-               clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_enable(wdev->mpu_wdt_ick);    /* Enable the interface clock */
+               clk_enable(wdev->mpu_wdt_fck);    /* Enable the functional clock */
        }
 
        /* initialize prescaler */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
-       omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+
+       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       omap_wdt_set_timeout();
-       omap_wdt_enable();
+       file->private_data = (void *) wdev;
+
+       omap_wdt_set_timeout(wdev);
+       omap_wdt_enable(wdev);
+
        return nonseekable_open(inode, file);
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /*
         *      Shut off the timer unless NOWAYOUT is defined.
         */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
-       omap_wdt_disable();
 
-       if (cpu_is_omap16xx()) {
-               clk_disable(armwdt_ck); /* Disable the clock */
-               clk_put(armwdt_ck);
-               armwdt_ck = NULL;
-       }
+       omap_wdt_disable(wdev);
 
-       if (cpu_is_omap24xx()) {
-               clk_disable(mpu_wdt_ick);       /* Disable the clock */
-               clk_disable(mpu_wdt_fck);       /* Disable the clock */
-               clk_put(mpu_wdt_ick);
-               clk_put(mpu_wdt_fck);
-               mpu_wdt_ick = NULL;
-               mpu_wdt_fck = NULL;
+       if (cpu_is_omap16xx())
+               clk_disable(wdev->armwdt_ck);   /* Disable the clock */
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+               clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
        }
 #else
        printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+
        return 0;
 }
 
 static ssize_t omap_wdt_write(struct file *file, const char __user *data,
                size_t len, loff_t *ppos)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /* Refresh LOAD_TIME. */
        if (len) {
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
        }
        return len;
@@ -188,6 +213,7 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
 static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                                                unsigned long arg)
 {
+       struct omap_wdt_dev *wdev;
        int new_margin;
        static const struct watchdog_info ident = {
                .identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                .firmware_version = 0,
        };
 
+       wdev = file->private_data;
+
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                return put_user(0, (int __user *)arg);
        case WDIOC_GETBOOTSTATUS:
                if (cpu_is_omap16xx())
-                       return put_user(omap_readw(ARM_SYSST),
+                       return put_user(__raw_readw(ARM_SYSST),
                                        (int __user *)arg);
                if (cpu_is_omap24xx())
                        return put_user(omap_prcm_get_reset_sources(),
                                        (int __user *)arg);
        case WDIOC_KEEPALIVE:
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                return 0;
        case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                omap_wdt_adjust_timeout(new_margin);
 
                spin_lock(&wdt_lock);
-               omap_wdt_disable();
-               omap_wdt_set_timeout();
-               omap_wdt_enable();
+               omap_wdt_disable(wdev);
+               omap_wdt_set_timeout(wdev);
+               omap_wdt_enable(wdev);
 
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                /* Fall */
        case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@ static const struct file_operations omap_wdt_fops = {
        .release = omap_wdt_release,
 };
 
-static struct miscdevice omap_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &omap_wdt_fops,
-};
-
 static int __init omap_wdt_probe(struct platform_device *pdev)
 {
        struct resource *res, *mem;
+       struct omap_wdt_dev *wdev;
        int ret;
 
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
+       if (!res) {
+               ret = -ENOENT;
+               goto err_get_resource;
+       }
+
+       if (omap_wdt_dev) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
+       if (!mem) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
-       platform_set_drvdata(pdev, mem);
+       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+       if (!wdev) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
 
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+       wdev->mem = mem;
 
        if (cpu_is_omap16xx()) {
-               armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
-               if (IS_ERR(armwdt_ck)) {
-                       ret = PTR_ERR(armwdt_ck);
-                       armwdt_ck = NULL;
-                       goto fail;
+               wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+               if (IS_ERR(wdev->armwdt_ck)) {
+                       ret = PTR_ERR(wdev->armwdt_ck);
+                       wdev->armwdt_ck = NULL;
+                       goto err_clk;
                }
        }
 
        if (cpu_is_omap24xx()) {
-               mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
-               if (IS_ERR(mpu_wdt_ick)) {
-                       ret = PTR_ERR(mpu_wdt_ick);
-                       mpu_wdt_ick = NULL;
-                       goto fail;
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
                }
-               mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
-               if (IS_ERR(mpu_wdt_fck)) {
-                       ret = PTR_ERR(mpu_wdt_fck);
-                       mpu_wdt_fck = NULL;
-                       goto fail;
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
                }
        }
 
-       omap_wdt_disable();
+       if (cpu_is_omap34xx()) {
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
+               }
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
+               }
+       }
+       wdev->base = ioremap(res->start, res->end - res->start + 1);
+       if (!wdev->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       platform_set_drvdata(pdev, wdev);
+
+       omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
 
-       omap_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&omap_wdt_miscdev);
+       wdev->omap_wdt_miscdev.parent = &pdev->dev;
+       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+       wdev->omap_wdt_miscdev.name = "watchdog";
+       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+       ret = misc_register(&(wdev->omap_wdt_miscdev));
        if (ret)
-               goto fail;
+               goto err_misc;
 
-       pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+       pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+               __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+               timer_margin);
 
        /* autogate OCP interface clock */
-       omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+       __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+       omap_wdt_dev = pdev;
+
        return 0;
 
-fail:
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
-       release_resource(mem);
+err_misc:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(wdev->base);
+
+err_ioremap:
+       wdev->base = NULL;
+
+err_clk:
+       if (wdev->armwdt_ck)
+               clk_put(wdev->armwdt_ck);
+       if (wdev->mpu_wdt_ick)
+               clk_put(wdev->mpu_wdt_ick);
+       if (wdev->mpu_wdt_fck)
+               clk_put(wdev->mpu_wdt_fck);
+       kfree(wdev);
+
+err_kzalloc:
+       release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
        return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct resource *mem = platform_get_drvdata(pdev);
-       misc_deregister(&omap_wdt_miscdev);
-       release_resource(mem);
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!res)
+               return -ENOENT;
+
+       misc_deregister(&(wdev->omap_wdt_miscdev));
+       release_mem_region(res->start, res->end - res->start + 1);
+       platform_set_drvdata(pdev, NULL);
+
+       if (wdev->armwdt_ck) {
+               clk_put(wdev->armwdt_ck);
+               wdev->armwdt_ck = NULL;
+       }
+
+       if (wdev->mpu_wdt_ick) {
+               clk_put(wdev->mpu_wdt_ick);
+               wdev->mpu_wdt_ick = NULL;
+       }
+
+       if (wdev->mpu_wdt_fck) {
+               clk_put(wdev->mpu_wdt_fck);
+               wdev->mpu_wdt_fck = NULL;
+       }
+       iounmap(wdev->base);
+
+       kfree(wdev);
+       omap_wdt_dev = NULL;
+
        return 0;
 }
 
@@ -344,17 +449,23 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (omap_wdt_users)
-               omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
+
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       if (omap_wdt_users) {
-               omap_wdt_enable();
-               omap_wdt_ping();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users) {
+               omap_wdt_enable(wdev);
+               omap_wdt_ping(wdev);
        }
+
        return 0;
 }
 
index 52a532a5114a94795e715d554e5aa57c584917ce..fc02ec6a03869a6a6bb0daa9889b1ebf10d558ec 100644 (file)
 #ifndef _OMAP_WATCHDOG_H
 #define _OMAP_WATCHDOG_H
 
-#define OMAP1610_WATCHDOG_BASE         0xfffeb000
-#define OMAP2420_WATCHDOG_BASE         0x48022000      /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE             OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE             OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP                  0
-#endif
-
-#define OMAP_WATCHDOG_REV              (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG       (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS           (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL            (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR              (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR              (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR              (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS              (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR              (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV              (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG       (0x10)
+#define OMAP_WATCHDOG_STATUS           (0x14)
+#define OMAP_WATCHDOG_CNTRL            (0x24)
+#define OMAP_WATCHDOG_CRR              (0x28)
+#define OMAP_WATCHDOG_LDR              (0x2c)
+#define OMAP_WATCHDOG_TGR              (0x30)
+#define OMAP_WATCHDOG_WPS              (0x34)
+#define OMAP_WATCHDOG_SPR              (0x48)
 
 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
index e02c15d158fc978d72e0b0647c87391a446af76b..e1bf4707aa7a244cc030486ff02a9be15221482d 100644 (file)
@@ -1,2 +1,3 @@
 arch
+asm-offsets.h
 mach-types.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 0f99ad38b012f93ef10ccb5b0f9105b4e7f8daab..e71e1e82e68a2ea2d4390c55ae393807ae69ef7c 100644 (file)
@@ -40,6 +40,8 @@ struct module;
  *     returns either the value actually sensed, or zero
  * @direction_output: configures signal "offset" as output, or returns error
  * @set: assigns output value for signal "offset"
+ * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
+ *     implementation may not sleep
  * @dbg_show: optional routine to show contents in debugfs; default code
  *     will be used when this is omitted, but custom code can show extra
  *     state (such as pullup/pulldown configuration).
@@ -73,6 +75,10 @@ struct gpio_chip {
                                                unsigned offset, int value);
        void                    (*set)(struct gpio_chip *chip,
                                                unsigned offset, int value);
+
+       int                     (*to_irq)(struct gpio_chip *chip,
+                                               unsigned offset);
+
        void                    (*dbg_show)(struct seq_file *s,
                                                struct gpio_chip *chip);
        int                     base;
@@ -112,6 +118,7 @@ extern void __gpio_set_value(unsigned gpio, int value);
 
 extern int __gpio_cansleep(unsigned gpio);
 
+extern int __gpio_to_irq(unsigned gpio);
 
 #ifdef CONFIG_GPIO_SYSFS
 
index 5c7f9468f753b51fb05a0417930cffb2e709f59f..4c3cb6d77de8dc6e201fc9194bdefad9bba1aec4 100644 (file)
@@ -36,6 +36,8 @@
 #define CN_VAL_CIFS                     0x1
 #define CN_W1_IDX                      0x3     /* w1 communication */
 #define CN_W1_VAL                      0x1
+#define CN_IDX_SX1SND                  0x4
+#define CN_VAL_SX1SND                  0x1
 #define CN_IDX_V86D                    0x4
 #define CN_VAL_V86D_UVESAFB            0x1
 #define CN_IDX_BB                      0x5     /* BlackBoard, from the TSP GPL sampling framework */
index bf34c5f4c0511abc17c664655559918e2da01ef5..3ae0f7660135148c813e2ad1cfd9682d90625508 100644 (file)
 
 #define I2C_DRIVERID_MSP3400    1
 #define I2C_DRIVERID_TUNER      2
+#define I2C_DRIVERID_TDA8425    4      /* stereo sound processor       */
 #define I2C_DRIVERID_TEA6420    5      /* audio matrix switch          */
 #define I2C_DRIVERID_TEA6415C   6      /* video matrix switch          */
 #define I2C_DRIVERID_TDA9840    7      /* stereo sound processor       */
 #define I2C_DRIVERID_SAA7111A   8      /* video input processor        */
 #define I2C_DRIVERID_SAA7185B  13      /* video encoder                */
+#define I2C_DRIVERID_TEA6300   18      /* audio mixer                  */
+#define I2C_DRIVERID_TDA9850   20      /* audio mixer                  */
+#define I2C_DRIVERID_TDA9855   21      /* audio mixer                  */
 #define I2C_DRIVERID_SAA7110   22      /* video decoder                */
 #define I2C_DRIVERID_SAA5249   24      /* SAA5249 and compatibles      */
 #define I2C_DRIVERID_PCF8583   25      /* real time clock              */
@@ -45,7 +49,9 @@
 #define I2C_DRIVERID_TDA7432   27      /* Stereo sound processor       */
 #define I2C_DRIVERID_TVMIXER    28      /* Mixer driver for tv cards    */
 #define I2C_DRIVERID_TVAUDIO    29      /* Generic TV sound driver      */
+#define I2C_DRIVERID_TDA9873    31      /* TV sound decoder chip        */
 #define I2C_DRIVERID_TDA9875    32      /* TV sound decoder chip        */
+#define I2C_DRIVERID_PIC16C54_PV9 33    /* Audio mux/ir receiver        */
 #define I2C_DRIVERID_BT819     40     /* video decoder                 */
 #define I2C_DRIVERID_BT856     41     /* video encoder                 */
 #define I2C_DRIVERID_VPX3220   42     /* video decoder+vbi/vtxt        */
@@ -56,6 +62,7 @@
 #define I2C_DRIVERID_INDYCAM   58      /* SGI IndyCam                  */
 #define I2C_DRIVERID_OVCAMCHIP 61      /* OmniVision CMOS image sens.  */
 #define I2C_DRIVERID_MAX6900   63      /* MAX6900 real-time clock      */
+#define I2C_DRIVERID_TDA9874   66      /* TV sound decoder             */
 #define I2C_DRIVERID_SAA6752HS 67      /* MPEG2 encoder                */
 #define I2C_DRIVERID_TVEEPROM  68      /* TV EEPROM                    */
 #define I2C_DRIVERID_WM8775    69      /* wm8775 audio processor       */
 #define I2C_DRIVERID_M52790    95      /* Mitsubishi M52790SP/FP AV switch */
 #define I2C_DRIVERID_CS5345    96      /* cs5345 audio processor       */
 
+#define I2C_DRIVERID_MISC      99      /* Whatever until sorted out    */
+
+#define I2C_DRIVERID_I2CDEV    900
+
 #define I2C_DRIVERID_OV7670 1048       /* Omnivision 7670 camera */
 
 /*
 #define I2C_HW_B_RIVA          0x010010 /* Riva based graphics cards */
 #define I2C_HW_B_IOC           0x010011 /* IOC bit-wiggling */
 #define I2C_HW_B_IXP2000       0x010016 /* GPIO on IXP2000 systems */
+#define I2C_HW_B_S3VIA         0x010018 /* S3Via ProSavage adapter */
 #define I2C_HW_B_ZR36067       0x010019 /* Zoran-36057/36067 based boards */
 #define I2C_HW_B_PCILYNX       0x01001a /* TI PCILynx I2C adapter */
 #define I2C_HW_B_CX2388x       0x01001b /* connexant 2388x based tv cards */
 #define I2C_HW_SMBUS_W9968CF   0x04000d
 #define I2C_HW_SMBUS_OV511     0x04000e /* OV511(+) USB 1.1 webcam ICs */
 #define I2C_HW_SMBUS_OV518     0x04000f /* OV518(+) USB 1.1 webcam ICs */
+#define I2C_HW_SMBUS_OVFX2     0x040011 /* Cypress/OmniVision FX2 webcam */
 #define I2C_HW_SMBUS_CAFE      0x040012 /* Marvell 88ALP01 "CAFE" cam  */
 #define I2C_HW_SMBUS_ALI1563   0x040013
 
diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h
new file mode 100644 (file)
index 0000000..17d6b33
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * include/lm8323.h
+ *
+ * Configuration for LM8323 keypad driver.
+ */
+
+#ifndef __LINUX_LM8323_H
+#define __LINUX_LM8323_H
+
+#include <linux/types.h>
+
+/*
+ * Largest keycode that the chip can send, plus one,
+ * so keys can be mapped directly at the index of the
+ * LM8323 keycode instead of subtracting one.
+ */
+#define LM8323_KEYMAP_SIZE (0x7f + 1)
+
+struct lm8323_platform_data {
+       int debounce_time; /* Time to watch for key bouncing, in ms. */
+       int active_time; /* Idle time until sleep, in ms. */
+
+       int size_x;
+       int size_y;
+       int repeat : 1;
+       const s16 *keymap;
+
+       char *pwm1_name; /* Device name for PWM1. */
+       char *pwm2_name; /* Device name for PWM2. */
+       char *pwm3_name; /* Device name for PWM3. */
+
+       char *name; /* Device name. */
+};
+
+void __init lm8323_set_platform_data(struct lm8323_platform_data *pdata);
+
+#endif /* __LINUX_LM8323_H */
diff --git a/include/linux/i2c/menelaus.h b/include/linux/i2c/menelaus.h
new file mode 100644 (file)
index 0000000..9587398
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * include/linux/i2c/menelaus.h
+ *
+ * Functions to access Menelaus power management chip
+ */
+
+#ifndef __ASM_ARCH_MENELAUS_H
+#define __ASM_ARCH_MENELAUS_H
+
+#define MENELAUS_I2C_ADDRESS           0x72
+
+#define MENELAUS_REV                   0x01
+#define MENELAUS_VCORE_CTRL1           0x02
+#define MENELAUS_VCORE_CTRL2           0x03
+#define MENELAUS_VCORE_CTRL3           0x04
+#define MENELAUS_VCORE_CTRL4           0x05
+#define MENELAUS_VCORE_CTRL5           0x06
+#define MENELAUS_DCDC_CTRL1            0x07
+#define MENELAUS_DCDC_CTRL2            0x08
+#define MENELAUS_DCDC_CTRL3            0x09
+#define MENELAUS_LDO_CTRL1             0x0A
+#define MENELAUS_LDO_CTRL2             0x0B
+#define MENELAUS_LDO_CTRL3             0x0C
+#define MENELAUS_LDO_CTRL4             0x0D
+#define MENELAUS_LDO_CTRL5             0x0E
+#define MENELAUS_LDO_CTRL6             0x0F
+#define MENELAUS_LDO_CTRL7             0x10
+#define MENELAUS_LDO_CTRL8             0x11
+#define MENELAUS_SLEEP_CTRL1           0x12
+#define MENELAUS_SLEEP_CTRL2           0x13
+#define MENELAUS_DEVICE_OFF            0x14
+#define MENELAUS_OSC_CTRL              0x15
+#define MENELAUS_DETECT_CTRL           0x16
+#define MENELAUS_INT_MASK1             0x17
+#define MENELAUS_INT_MASK2             0x18
+#define MENELAUS_INT_STATUS1           0x19
+#define MENELAUS_INT_STATUS2           0x1A
+#define MENELAUS_INT_ACK1              0x1B
+#define MENELAUS_INT_ACK2              0x1C
+#define MENELAUS_GPIO_CTRL             0x1D
+#define MENELAUS_GPIO_IN               0x1E
+#define MENELAUS_GPIO_OUT              0x1F
+#define MENELAUS_BBSMS                 0x20
+#define MENELAUS_RTC_CTRL              0x21
+#define MENELAUS_RTC_UPDATE            0x22
+#define MENELAUS_RTC_SEC               0x23
+#define MENELAUS_RTC_MIN               0x24
+#define MENELAUS_RTC_HR                        0x25
+#define MENELAUS_RTC_DAY               0x26
+#define MENELAUS_RTC_MON               0x27
+#define MENELAUS_RTC_YR                        0x28
+#define MENELAUS_RTC_WKDAY             0x29
+#define MENELAUS_RTC_AL_SEC            0x2A
+#define MENELAUS_RTC_AL_MIN            0x2B
+#define MENELAUS_RTC_AL_HR             0x2C
+#define MENELAUS_RTC_AL_DAY            0x2D
+#define MENELAUS_RTC_AL_MON            0x2E
+#define MENELAUS_RTC_AL_YR             0x2F
+#define MENELAUS_RTC_COMP_MSB          0x30
+#define MENELAUS_RTC_COMP_LSB          0x31
+#define MENELAUS_S1_PULL_EN            0x32
+#define MENELAUS_S1_PULL_DIR           0x33
+#define MENELAUS_S2_PULL_EN            0x34
+#define MENELAUS_S2_PULL_DIR           0x35
+#define MENELAUS_MCT_CTRL1             0x36
+#define MENELAUS_MCT_CTRL2             0x37
+#define MENELAUS_MCT_CTRL3             0x38
+#define MENELAUS_MCT_PIN_ST            0x39
+#define MENELAUS_DEBOUNCE1             0x3A
+
+#define IH_MENELAUS_IRQS               12
+#define MENELAUS_MMC_S1CD_IRQ          0       /* MMC slot 1 card change */
+#define MENELAUS_MMC_S2CD_IRQ          1       /* MMC slot 2 card change */
+#define MENELAUS_MMC_S1D1_IRQ          2       /* MMC DAT1 low in slot 1 */
+#define MENELAUS_MMC_S2D1_IRQ          3       /* MMC DAT1 low in slot 2 */
+#define MENELAUS_LOWBAT_IRQ            4       /* Low battery */
+#define MENELAUS_HOTDIE_IRQ            5       /* Hot die detect */
+#define MENELAUS_UVLO_IRQ              6       /* UVLO detect */
+#define MENELAUS_TSHUT_IRQ             7       /* Thermal shutdown */
+#define MENELAUS_RTCTMR_IRQ            8       /* RTC timer */
+#define MENELAUS_RTCALM_IRQ            9       /* RTC alarm */
+#define MENELAUS_RTCERR_IRQ            10      /* RTC error */
+#define MENELAUS_PSHBTN_IRQ            11      /* Push button */
+#define MENELAUS_RESERVED12_IRQ                12      /* Reserved */
+#define MENELAUS_RESERVED13_IRQ                13      /* Reserved */
+#define MENELAUS_RESERVED14_IRQ                14      /* Reserved */
+#define MENELAUS_RESERVED15_IRQ                15      /* Reserved */
+
+/* VCORE_CTRL1 register */
+#define VCORE_CTRL1_BYP_COMP           (1 << 5)
+#define VCORE_CTRL1_HW_NSW             (1 << 7)
+
+/* GPIO_CTRL register */
+#define GPIO_CTRL_SLOTSELEN            (1 << 5)
+#define GPIO_CTRL_SLPCTLEN             (1 << 6)
+#define GPIO1_DIR_INPUT                (1 << 0)
+#define GPIO2_DIR_INPUT                (1 << 1)
+#define GPIO3_DIR_INPUT                (1 << 2)
+
+/* MCT_CTRL1 register */
+#define MCT_CTRL1_S1_CMD_OD            (1 << 2)
+#define MCT_CTRL1_S2_CMD_OD            (1 << 3)
+
+/* MCT_CTRL2 register */
+#define MCT_CTRL2_VS2_SEL_D0           (1 << 0)
+#define MCT_CTRL2_VS2_SEL_D1           (1 << 1)
+#define MCT_CTRL2_S1CD_BUFEN           (1 << 4)
+#define MCT_CTRL2_S2CD_BUFEN           (1 << 5)
+#define MCT_CTRL2_S1CD_DBEN            (1 << 6)
+#define MCT_CTRL2_S2CD_BEN             (1 << 7)
+
+/* MCT_CTRL3 register */
+#define MCT_CTRL3_SLOT1_EN             (1 << 0)
+#define MCT_CTRL3_SLOT2_EN             (1 << 1)
+#define MCT_CTRL3_S1_AUTO_EN           (1 << 2)
+#define MCT_CTRL3_S2_AUTO_EN           (1 << 3)
+
+/* MCT_PIN_ST register */
+#define MCT_PIN_ST_S1_CD_ST            (1 << 0)
+#define MCT_PIN_ST_S2_CD_ST            (1 << 1)
+
+struct device;
+
+struct menelaus_platform_data {
+       int (*late_init)(struct device *dev);
+};
+
+extern int menelaus_register_mmc_callback(void (*callback)(void *data,
+                                         u8 card_mask),
+                                         void *data);
+extern void menelaus_unregister_mmc_callback(void);
+extern int menelaus_set_mmc_opendrain(int slot, int enable);
+extern int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_on);
+extern int menelaus_enable_slot(int slot, int enable);
+
+extern int menelaus_set_vmem(unsigned int mV);
+extern int menelaus_set_vio(unsigned int mV);
+extern int menelaus_set_vmmc(unsigned int mV);
+extern int menelaus_set_vaux(unsigned int mV);
+extern int menelaus_set_vdcdc(int dcdc, unsigned int mV);
+extern int menelaus_set_slot_sel(int enable);
+extern int menelaus_get_slot_pin_states(void);
+extern int menelaus_set_vcore_sw(unsigned int mV);
+extern int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV);
+
+#define EN_VPLL_SLEEP  (1 << 7)
+#define EN_VMMC_SLEEP  (1 << 6)
+#define EN_VAUX_SLEEP  (1 << 5)
+#define EN_VIO_SLEEP   (1 << 4)
+#define EN_VMEM_SLEEP  (1 << 3)
+#define EN_DC3_SLEEP   (1 << 2)
+#define EN_DC2_SLEEP   (1 << 1)
+#define EN_VC_SLEEP    (1 << 0)
+
+extern int menelaus_set_regulator_sleep(int enable, u32 val);
+
+#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
+#define omap_has_menelaus()    1
+#else
+#define omap_has_menelaus()    0
+#endif
+
+#endif
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h
new file mode 100644 (file)
index 0000000..24523b5
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * include/linux/i2c/twl4030-madc.h
+ *
+ * TWL4030 MADC module driver header
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _TWL4030_MADC_H
+#define _TWL4030_MADC_H
+
+struct twl4030_madc_conversion_method {
+       u8 sel;
+       u8 avg;
+       u8 rbase;
+       u8 ctrl;
+};
+
+#define TWL4030_MADC_MAX_CHANNELS 16
+
+struct twl4030_madc_request {
+       u16 channels;
+       u16 do_avg;
+       u16 method;
+       u16 type;
+       int active;
+       int result_pending;
+       int rbuf[TWL4030_MADC_MAX_CHANNELS];
+       void (*func_cb)(int len, int channels, int *buf);
+};
+
+enum conversion_methods {
+       TWL4030_MADC_RT,
+       TWL4030_MADC_SW1,
+       TWL4030_MADC_SW2,
+       TWL4030_MADC_NUM_METHODS
+};
+
+enum sample_type {
+       TWL4030_MADC_WAIT,
+       TWL4030_MADC_IRQ_ONESHOT,
+       TWL4030_MADC_IRQ_REARM
+};
+
+#define TWL4030_MADC_CTRL1             0x00
+#define TWL4030_MADC_CTRL2             0x01
+
+#define TWL4030_MADC_RTSELECT_LSB      0x02
+#define TWL4030_MADC_SW1SELECT_LSB     0x06
+#define TWL4030_MADC_SW2SELECT_LSB     0x0A
+
+#define TWL4030_MADC_RTAVERAGE_LSB     0x04
+#define TWL4030_MADC_SW1AVERAGE_LSB    0x08
+#define TWL4030_MADC_SW2AVERAGE_LSB    0x0C
+
+#define TWL4030_MADC_CTRL_SW1          0x12
+#define TWL4030_MADC_CTRL_SW2          0x13
+
+#define TWL4030_MADC_RTCH0_LSB         0x17
+#define TWL4030_MADC_GPCH0_LSB         0x37
+
+#define TWL4030_MADC_MADCON            (1<<0)  /* MADC power on */
+#define TWL4030_MADC_BUSY              (1<<0)  /* MADC busy */
+#define TWL4030_MADC_EOC_SW            (1<<1)  /* MADC conversion completion */
+#define TWL4030_MADC_SW_START          (1<<5)  /* MADC SWx start conversion */
+
+#define        TWL4030_MADC_ADCIN0             (1<<0)
+#define        TWL4030_MADC_ADCIN1             (1<<1)
+#define        TWL4030_MADC_ADCIN2             (1<<2)
+#define        TWL4030_MADC_ADCIN3             (1<<3)
+#define        TWL4030_MADC_ADCIN4             (1<<4)
+#define        TWL4030_MADC_ADCIN5             (1<<5)
+#define        TWL4030_MADC_ADCIN6             (1<<6)
+#define        TWL4030_MADC_ADCIN7             (1<<7)
+#define        TWL4030_MADC_ADCIN8             (1<<8)
+#define        TWL4030_MADC_ADCIN9             (1<<9)
+#define        TWL4030_MADC_ADCIN10            (1<<10)
+#define        TWL4030_MADC_ADCIN11            (1<<11)
+#define        TWL4030_MADC_ADCIN12            (1<<12)
+#define        TWL4030_MADC_ADCIN13            (1<<13)
+#define        TWL4030_MADC_ADCIN14            (1<<14)
+#define        TWL4030_MADC_ADCIN15            (1<<15)
+
+/* Fixed channels */
+#define TWL4030_MADC_BTEMP             TWL4030_MADC_ADCIN1
+#define TWL4030_MADC_VBUS              TWL4030_MADC_ADCIN8
+#define TWL4030_MADC_VBKB              TWL4030_MADC_ADCIN9
+#define        TWL4030_MADC_ICHG               TWL4030_MADC_ADCIN10
+#define TWL4030_MADC_VCHG              TWL4030_MADC_ADCIN11
+#define        TWL4030_MADC_VBAT               TWL4030_MADC_ADCIN12
+
+/* BCI related - XXX To be moved elsewhere */
+#define TWL4030_BCI_BCICTL1            0x23
+#define        TWL4030_BCI_MESBAT              (1<<1)
+#define        TWL4030_BCI_TYPEN               (1<<4)
+#define        TWL4030_BCI_ITHEN               (1<<3)
+
+#define TWL4030_MADC_IOC_MAGIC '`'
+#define TWL4030_MADC_IOCX_ADC_RAW_READ         _IO(TWL4030_MADC_IOC_MAGIC, 0)
+
+struct twl4030_madc_user_parms {
+       int channel;
+       int average;
+       int status;
+       u16 result;
+};
+
+int twl4030_madc_conversion(struct twl4030_madc_request *conv);
+
+#endif
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
new file mode 100644 (file)
index 0000000..cdb4531
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * 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_
+
+/*
+ * Using the twl4030 core we address registers using a pair
+ *     { module id, relative register offset }
+ * which that core then maps to the relevant
+ *     { i2c slave, absolute register address }
+ *
+ * The module IDs are meaningful only to the twl4030 core code,
+ * which uses them as array indices to look up the first register
+ * address each module uses within a given i2c slave.
+ */
+
+/* Slave 0 (i2c address 0x48) */
+#define TWL4030_MODULE_USB             0x00
+
+/* Slave 1 (i2c address 0x49) */
+#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
+
+/* Slave 2 (i2c address 0x4a) */
+#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
+
+/* Slave 3 (i2c address 0x4b) */
+#define TWL4030_MODULE_BACKUP          0x10
+#define TWL4030_MODULE_INT             0x11
+#define TWL4030_MODULE_PM_MASTER       0x12
+#define TWL4030_MODULE_PM_RECEIVER     0x13
+#define TWL4030_MODULE_RTC             0x14
+#define TWL4030_MODULE_SECURED_REG     0x15
+
+/*
+ * Read and write single 8-bit registers
+ */
+int twl4030_i2c_write_u8(u8 mod_no, u8 val, u8 reg);
+int twl4030_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
+
+/*
+ * Read and write several 8-bit registers at once.
+ *
+ * IMPORTANT:  For twl4030_i2c_write(), allocate num_bytes + 1
+ * for the value, and populate your data starting 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);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * NOTE:  at up to 1024 registers, this is a big chip.
+ *
+ * Avoid putting register declarations in this file, instead of into
+ * a driver-private file, unless some of the registers in a block
+ * need to be shared with other drivers.  One example is blocks that
+ * have Secondary IRQ Handler (SIH) registers.
+ */
+
+#define TWL4030_SIH_CTRL_EXCLEN_MASK   BIT(0)
+#define TWL4030_SIH_CTRL_PENDDIS_MASK  BIT(1)
+#define TWL4030_SIH_CTRL_COR_MASK      BIT(2)
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * GPIO Block Register offsets (use TWL4030_MODULE_GPIO)
+ */
+
+#define REG_GPIODATAIN1                        0x0
+#define REG_GPIODATAIN2                        0x1
+#define REG_GPIODATAIN3                        0x2
+#define REG_GPIODATADIR1               0x3
+#define REG_GPIODATADIR2               0x4
+#define REG_GPIODATADIR3               0x5
+#define REG_GPIODATAOUT1               0x6
+#define REG_GPIODATAOUT2               0x7
+#define REG_GPIODATAOUT3               0x8
+#define REG_CLEARGPIODATAOUT1          0x9
+#define REG_CLEARGPIODATAOUT2          0xA
+#define REG_CLEARGPIODATAOUT3          0xB
+#define REG_SETGPIODATAOUT1            0xC
+#define REG_SETGPIODATAOUT2            0xD
+#define REG_SETGPIODATAOUT3            0xE
+#define REG_GPIO_DEBEN1                        0xF
+#define REG_GPIO_DEBEN2                        0x10
+#define REG_GPIO_DEBEN3                        0x11
+#define REG_GPIO_CTRL                  0x12
+#define REG_GPIOPUPDCTR1               0x13
+#define REG_GPIOPUPDCTR2               0x14
+#define REG_GPIOPUPDCTR3               0x15
+#define REG_GPIOPUPDCTR4               0x16
+#define REG_GPIOPUPDCTR5               0x17
+#define REG_GPIO_ISR1A                 0x19
+#define REG_GPIO_ISR2A                 0x1A
+#define REG_GPIO_ISR3A                 0x1B
+#define REG_GPIO_IMR1A                 0x1C
+#define REG_GPIO_IMR2A                 0x1D
+#define REG_GPIO_IMR3A                 0x1E
+#define REG_GPIO_ISR1B                 0x1F
+#define REG_GPIO_ISR2B                 0x20
+#define REG_GPIO_ISR3B                 0x21
+#define REG_GPIO_IMR1B                 0x22
+#define REG_GPIO_IMR2B                 0x23
+#define REG_GPIO_IMR3B                 0x24
+#define REG_GPIO_EDR1                  0x28
+#define REG_GPIO_EDR2                  0x29
+#define REG_GPIO_EDR3                  0x2A
+#define REG_GPIO_EDR4                  0x2B
+#define REG_GPIO_EDR5                  0x2C
+#define REG_GPIO_SIH_CTRL              0x2D
+
+/* Up to 18 signals are available as GPIOs, when their
+ * pins are not assigned to another use (such as ULPI/USB).
+ */
+#define TWL4030_GPIO_MAX               18
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Keypad register offsets (use TWL4030_MODULE_KEYPAD)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_KEYPAD_KEYP_ISR1       0x11
+#define TWL4030_KEYPAD_KEYP_IMR1       0x12
+#define TWL4030_KEYPAD_KEYP_ISR2       0x13
+#define TWL4030_KEYPAD_KEYP_IMR2       0x14
+#define TWL4030_KEYPAD_KEYP_SIR                0x15    /* test register */
+#define TWL4030_KEYPAD_KEYP_EDR                0x16
+#define TWL4030_KEYPAD_KEYP_SIH_CTRL   0x17
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Multichannel ADC register offsets (use TWL4030_MODULE_MADC)
+ * ... SIH/interrupt only
+ */
+
+#define TWL4030_MADC_ISR1              0x61
+#define TWL4030_MADC_IMR1              0x62
+#define TWL4030_MADC_ISR2              0x63
+#define TWL4030_MADC_IMR2              0x64
+#define TWL4030_MADC_SIR               0x65    /* test register */
+#define TWL4030_MADC_EDR               0x66
+#define TWL4030_MADC_SIH_CTRL          0x67
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Battery charger register offsets (use TWL4030_MODULE_INTERRUPTS)
+ */
+
+#define TWL4030_INTERRUPTS_BCIISR1A    0x0
+#define TWL4030_INTERRUPTS_BCIISR2A    0x1
+#define TWL4030_INTERRUPTS_BCIIMR1A    0x2
+#define TWL4030_INTERRUPTS_BCIIMR2A    0x3
+#define TWL4030_INTERRUPTS_BCIISR1B    0x4
+#define TWL4030_INTERRUPTS_BCIISR2B    0x5
+#define TWL4030_INTERRUPTS_BCIIMR1B    0x6
+#define TWL4030_INTERRUPTS_BCIIMR2B    0x7
+#define TWL4030_INTERRUPTS_BCISIR1     0x8     /* test register */
+#define TWL4030_INTERRUPTS_BCISIR2     0x9     /* test register */
+#define TWL4030_INTERRUPTS_BCIEDR1     0xa
+#define TWL4030_INTERRUPTS_BCIEDR2     0xb
+#define TWL4030_INTERRUPTS_BCIEDR3     0xc
+#define TWL4030_INTERRUPTS_BCISIHCTRL  0xd
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Power Interrupt block register offsets (use TWL4030_MODULE_INT)
+ */
+
+#define TWL4030_INT_PWR_ISR1           0x0
+#define TWL4030_INT_PWR_IMR1           0x1
+#define TWL4030_INT_PWR_ISR2           0x2
+#define TWL4030_INT_PWR_IMR2           0x3
+#define TWL4030_INT_PWR_SIR            0x4     /* test register */
+#define TWL4030_INT_PWR_EDR1           0x5
+#define TWL4030_INT_PWR_EDR2           0x6
+#define TWL4030_INT_PWR_SIH_CTRL       0x7
+
+/*----------------------------------------------------------------------*/
+
+struct twl4030_bci_platform_data {
+       int *battery_tmp_tbl;
+       unsigned int tblsize;
+};
+
+/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
+struct twl4030_gpio_platform_data {
+       int             gpio_base;
+       unsigned        irq_base, irq_end;
+
+       /* For gpio-N, bit (1 << N) in "pullups" is set if that pullup
+        * should be enabled.  Else, if that bit is set in "pulldowns",
+        * that pulldown is enabled.  Don't waste power by letting any
+        * digital inputs float...
+        */
+       u32             pullups;
+       u32             pulldowns;
+
+       int             (*setup)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+       int             (*teardown)(struct device *dev,
+                               unsigned gpio, unsigned ngpio);
+};
+
+struct twl4030_madc_platform_data {
+       int             irq_line;
+};
+
+struct twl4030_keypad_data {
+       int rows;
+       int cols;
+       int *keymap;
+       int irq;
+       unsigned int keymapsize;
+       unsigned int rep:1;
+};
+
+enum twl4030_usb_mode {
+       T2_USB_MODE_ULPI = 1,
+       T2_USB_MODE_CEA2011_3PIN = 2,
+};
+
+struct twl4030_usb_data {
+       enum twl4030_usb_mode   usb_mode;
+};
+
+struct twl4030_platform_data {
+       unsigned                                irq_base, irq_end;
+       struct twl4030_bci_platform_data        *bci;
+       struct twl4030_gpio_platform_data       *gpio;
+       struct twl4030_madc_platform_data       *madc;
+       struct twl4030_keypad_data              *keypad;
+       struct twl4030_usb_data                 *usb;
+
+       /* REVISIT more to come ... _nothing_ should be hard-wired */
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the
+ * IRQ data to subsidiary devices using platform device resources.
+ */
+
+/* IRQ information-need base */
+#include <mach/irqs.h>
+/* TWL4030 interrupts */
+
+/* #define TWL4030_MODIRQ_GPIO         (TWL4030_IRQ_BASE + 0) */
+#define TWL4030_MODIRQ_KEYPAD          (TWL4030_IRQ_BASE + 1)
+#define TWL4030_MODIRQ_BCI             (TWL4030_IRQ_BASE + 2)
+#define TWL4030_MODIRQ_MADC            (TWL4030_IRQ_BASE + 3)
+/* #define TWL4030_MODIRQ_USB          (TWL4030_IRQ_BASE + 4) */
+#define TWL4030_MODIRQ_PWR             (TWL4030_IRQ_BASE + 5)
+
+#define TWL4030_PWRIRQ_PWRBTN          (TWL4030_PWR_IRQ_BASE + 0)
+#define TWL4030_PWRIRQ_CHG_PRES                (TWL4030_PWR_IRQ_BASE + 1)
+#define TWL4030_PWRIRQ_USB_PRES                (TWL4030_PWR_IRQ_BASE + 2)
+#define TWL4030_PWRIRQ_RTC             (TWL4030_PWR_IRQ_BASE + 3)
+#define TWL4030_PWRIRQ_HOT_DIE         (TWL4030_PWR_IRQ_BASE + 4)
+#define TWL4030_PWRIRQ_PWROK_TIMEOUT   (TWL4030_PWR_IRQ_BASE + 5)
+#define TWL4030_PWRIRQ_MBCHG           (TWL4030_PWR_IRQ_BASE + 6)
+#define TWL4030_PWRIRQ_SC_DETECT       (TWL4030_PWR_IRQ_BASE + 7)
+
+/* Rest are unsued currently*/
+
+/* Offsets to Power Registers */
+#define TWL4030_VDAC_DEV_GRP           0x3B
+#define TWL4030_VDAC_DEDICATED         0x3E
+#define TWL4030_VAUX1_DEV_GRP          0x17
+#define TWL4030_VAUX1_DEDICATED                0x1A
+#define TWL4030_VAUX2_DEV_GRP          0x1B
+#define TWL4030_VAUX2_DEDICATED                0x1E
+#define TWL4030_VAUX3_DEV_GRP          0x1F
+#define TWL4030_VAUX3_DEDICATED                0x22
+
+/* TWL4030 GPIO interrupt definitions */
+
+#define TWL4030_GPIO_IRQ_NO(n)         (TWL4030_GPIO_IRQ_BASE + (n))
+#define TWL4030_GPIO_IS_ENABLE         1
+
+/*
+ * Exported TWL4030 GPIO APIs
+ *
+ * WARNING -- use standard GPIO and IRQ calls instead; these will vanish.
+ */
+int twl4030_get_gpio_datain(int gpio);
+int twl4030_request_gpio(int gpio);
+int twl4030_set_gpio_debounce(int gpio, int enable);
+int twl4030_free_gpio(int gpio);
+
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+       defined(CONFIG_TWL4030_BCI_BATTERY_MODULE)
+       extern int twl4030charger_usb_en(int enable);
+#else
+       static inline int twl4030charger_usb_en(int enable) { return 0; }
+#endif
+
+#endif /* End of __TWL4030_H */
index 29f62e1733ff4e23c61e4f25c75d6e5498e4ab93..17065f7681a036cd27494cef8f94be05137dc23e 100644 (file)
@@ -41,6 +41,9 @@ extern unsigned int __kfifo_put(struct kfifo *fifo,
                                unsigned char *buffer, unsigned int len);
 extern unsigned int __kfifo_get(struct kfifo *fifo,
                                unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_get_to_user(struct kfifo *fifo,
+                                       unsigned char __user *buffer,
+                                       unsigned int len);
 
 /**
  * __kfifo_reset - removes the entire FIFO contents, no locking version
@@ -149,4 +152,36 @@ static inline unsigned int kfifo_len(struct kfifo *fifo)
        return ret;
 }
 
+/**
+ * kfifo_get_to_user - gets some data from the FIFO
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied. user buffer
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * user @buffer and returns the number of copied bytes.
+ */
+static inline unsigned int kfifo_get_to_user(struct kfifo *fifo,
+                                            unsigned char __user *buffer,
+                                            unsigned int len)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(fifo->lock, flags);
+
+       ret = __kfifo_get_to_user(fifo, buffer, len);
+
+       /*
+        * optimization: if the FIFO is empty, set the indices to 0
+        * so we don't wrap the next time
+        */
+       if (fifo->in == fifo->out)
+               fifo->in = fifo->out = 0;
+
+       spin_unlock_irqrestore(fifo->lock, flags);
+
+       return ret;
+}
+
 #endif
index 81774e5facf4e74a2d5dd742bae6bb81a1922b17..aac285162dd1b36a2855c6697beacbe754f99243 100644 (file)
@@ -45,7 +45,7 @@ extern void nand_wait_ready(struct mtd_info *mtd);
  */
 #define NAND_MAX_OOBSIZE       64
 #define NAND_MAX_PAGESIZE      2048
-
+#define NAND_BLOCK_SIZE                SZ_128K
 /*
  * Constants for hardware specific CLE/ALE/NCE function
  *
index d1b310c92eb45a9272c8ba2ac30c26becb856a5e..0c6bbe28f38ce91e01151faa517c75688300488b 100644 (file)
 #define ONENAND_SYS_CFG1_INT           (1 << 6)
 #define ONENAND_SYS_CFG1_IOBE          (1 << 5)
 #define ONENAND_SYS_CFG1_RDY_CONF      (1 << 4)
+#define ONENAND_SYS_CFG1_HF            (1 << 2)
+#define ONENAND_SYS_CFG1_SYNC_WRITE    (1 << 1)
 
 /*
  * Controller Status Register F240h (R)
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 daf744017a31c86bfaacf0a98ad1ebfdd27a4595..37c75fbacea2dbf4406779295a17c975d35854bc 100644 (file)
@@ -48,5 +48,10 @@ struct ads7846_platform_data {
                                 void **filter_data);
        int     (*filter)       (void *filter_data, int data_idx, int *val);
        void    (*filter_cleanup)(void *filter_data);
+
+       /* controls enabling/disabling*/
+       int     (*vaux_control)(int vaux_cntrl);
+#define VAUX_ENABLE    1
+#define VAUX_DISABLE   0
 };
 
diff --git a/include/linux/spi/tsc2005.h b/include/linux/spi/tsc2005.h
new file mode 100644 (file)
index 0000000..dbc01f7
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _LINUX_SPI_TSC2005_H
+#define _LINUX_SPI_TSC2005_H
+
+#include <linux/types.h>
+
+struct tsc2005_platform_data {
+       s16     reset_gpio;
+       s16     dav_gpio;
+       s16     pen_int_gpio;
+       u16     ts_x_plate_ohm;
+       u32     ts_stab_time;   /* voltage settling time */
+       u8      ts_hw_avg;      /* HW assiseted averaging. Can be
+                                  0, 4, 8, 16 samples per reading */
+       u32     ts_touch_pressure;      /* Pressure limit until we report a
+                                          touch event. After that we switch
+                                          to ts_max_pressure. */
+       u32     ts_pressure_max;/* Samples with bigger pressure value will
+                                  be ignored, since the corresponding X, Y
+                                  values are unreliable */
+       u32     ts_pressure_fudge;
+       u32     ts_x_max;
+       u32     ts_x_fudge;
+       u32     ts_y_max;
+       u32     ts_y_fudge;
+
+       unsigned ts_ignore_last : 1;
+};
+
+#endif
diff --git a/include/linux/spi/tsc2101.h b/include/linux/spi/tsc2101.h
new file mode 100644 (file)
index 0000000..01e6d23
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * include/linux/spi/tsc2101.h
+ *
+ * TSC2101 codec interface driver for the OMAP platform
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004/11/07   Nishanth Menon - Provided common hooks for Audio and Touchscreen
+ */
+
+#ifndef __OMAP_TSC2101_H
+#define __OMAP_TSC2101_H
+
+#include <linux/spi/spi.h>
+
+struct tsc2101_platform_data {
+       int     (*init)(struct spi_device *spi);
+       void    (*cleanup)(struct spi_device *spi);
+       void    (*enable_mclk)(struct spi_device *spi);
+       void    (*disable_mclk)(struct spi_device *spi);
+};
+
+extern int tsc2101_read_sync(struct spi_device *spi, int page, u8 address);
+extern int tsc2101_reads_sync(struct spi_device *spi, int page,
+                              u8 startaddress, u16 * data, int numregs);
+extern int tsc2101_write_sync(struct spi_device *spi, int page, u8 address,
+                              u16 data);
+
+extern int tsc2101_enable_mclk(struct spi_device *spi);
+extern void tsc2101_disable_mclk(struct spi_device *spi);
+
+#endif
+
diff --git a/include/linux/spi/tsc2102.h b/include/linux/spi/tsc2102.h
new file mode 100644 (file)
index 0000000..be13300
--- /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);
+
+#if defined(CONFIG_SND_OMAP_TSC2102) || defined(CONFIG_SND_OMAP_TSC2102_MODULE)
+extern void tsc2102_set_volume(uint8_t left_ch, uint8_t right_ch);
+extern void tsc2102_set_mute(int left_ch, int right_ch);
+extern void tsc2102_get_mute(int *left_ch, int *right_ch);
+extern void tsc2102_dac_power(int state);
+extern int tsc2102_set_rate(int rate);
+extern void tsc2102_set_i2s_master(int state);
+extern void tsc2102_set_deemphasis(int enable);
+extern void tsc2102_set_bassboost(int enable);
+#endif
+
+extern void tsc2102_keyclick(int amplitude, int freq, int length);
+
+#define TSC2102_REG(pg, addr)          pg, addr
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC2102_TS_X                   TSC2102_REG(0, 0x00)
+#define TSC2102_TS_Y                   TSC2102_REG(0, 0x01)
+#define TSC2102_TS_Z1                  TSC2102_REG(0, 0x02)
+#define TSC2102_TS_Z2                  TSC2102_REG(0, 0x03)
+#define TSC2102_TS_BAT1                        TSC2102_REG(0, 0x05)
+#define TSC2102_TS_BAT2                        TSC2102_REG(0, 0x06)
+#define TSC2102_TS_AUX                 TSC2102_REG(0, 0x07)
+#define TSC2102_TS_TEMP1               TSC2102_REG(0, 0x09)
+#define TSC2102_TS_TEMP2               TSC2102_REG(0, 0x0a)
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC2102_TS_ADC_CTRL            TSC2102_REG(1, 0x00)
+#define TSC2102_TS_STATUS_CTRL         TSC2102_REG(1, 0x01)
+#define TSC2102_TS_REF_CTRL            TSC2102_REG(1, 0x03)
+#define TSC2102_TS_RESET_CTRL          TSC2102_REG(1, 0x04)
+#define TSC2102_TS_CONFIG_CTRL         TSC2102_REG(1, 0x05)
+
+/* Page 2, Audio Control registers */
+#define TSC2102_AUDIO1_CTRL            TSC2102_REG(2, 0x00)
+#define TSC2102_DAC_GAIN_CTRL          TSC2102_REG(2, 0x02)
+#define TSC2102_AUDIO2_CTRL            TSC2102_REG(2, 0x04)
+#define TSC2102_DAC_POWER_CTRL         TSC2102_REG(2, 0x05)
+#define TSC2102_AUDIO3_CTRL            TSC2102_REG(2, 0x06)
+#define TSC2102_LCH_BASS_BOOST_N0      TSC2102_REG(2, 0x07)
+#define TSC2102_LCH_BASS_BOOST_N1      TSC2102_REG(2, 0x08)
+#define TSC2102_LCH_BASS_BOOST_N2      TSC2102_REG(2, 0x09)
+#define TSC2102_LCH_BASS_BOOST_N3      TSC2102_REG(2, 0x0a)
+#define TSC2102_LCH_BASS_BOOST_N4      TSC2102_REG(2, 0x0b)
+#define TSC2102_LCH_BASS_BOOST_N5      TSC2102_REG(2, 0x0c)
+#define TSC2102_LCH_BASS_BOOST_D1      TSC2102_REG(2, 0x0d)
+#define TSC2102_LCH_BASS_BOOST_D2      TSC2102_REG(2, 0x0e)
+#define TSC2102_LCH_BASS_BOOST_D4      TSC2102_REG(2, 0x0f)
+#define TSC2102_LCH_BASS_BOOST_D5      TSC2102_REG(2, 0x10)
+#define TSC2102_RCH_BASS_BOOST_N0      TSC2102_REG(2, 0x11)
+#define TSC2102_RCH_BASS_BOOST_N1      TSC2102_REG(2, 0x12)
+#define TSC2102_RCH_BASS_BOOST_N2      TSC2102_REG(2, 0x13)
+#define TSC2102_RCH_BASS_BOOST_N3      TSC2102_REG(2, 0x14)
+#define TSC2102_RCH_BASS_BOOST_N4      TSC2102_REG(2, 0x15)
+#define TSC2102_RCH_BASS_BOOST_N5      TSC2102_REG(2, 0x16)
+#define TSC2102_RCH_BASS_BOOST_D1      TSC2102_REG(2, 0x17)
+#define TSC2102_RCH_BASS_BOOST_D2      TSC2102_REG(2, 0x18)
+#define TSC2102_RCH_BASS_BOOST_D4      TSC2102_REG(2, 0x19)
+#define TSC2102_RCH_BASS_BOOST_D5      TSC2102_REG(2, 0x1a)
+#define TSC2102_PLL1_CTRL              TSC2102_REG(2, 0x1b)
+#define TSC2102_PLL2_CTRL              TSC2102_REG(2, 0x1c)
+#define TSC2102_AUDIO4_CTRL            TSC2102_REG(2, 0x1d)
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG)                  (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG)                 (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG)                 ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU                      (1 << 15)
+#define DGC_DALVL(ARG)                 (((ARG) & 0x7f) << 8)
+#define DGC_DARMU                      (1 << 7)
+#define DGC_DARVL(ARG)                 (((ARG) & 0x7f))
+
+/* Field formats for TSC2102_AUDIO2_CTRL */
+#define AC2_KCLEN                      (1 << 15)
+#define AC2_KCLAC(ARG)                 (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG)                        (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG)                 (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF                      (1 << 3)
+#define AC2_DRGAF                      (1 << 2)
+#define AC2_DASTC                      (1 << 1)
+
+/* Field masks for TSC2102_DAC_POWER_CTRL */
+#define CPC_PWDNC                      (1 << 15)
+#define CPC_DAODRC                     (1 << 12)
+#define CPC_DAPWDN                     (1 << 10)
+#define CPC_VGPWDN                     (1 << 8)
+#define CPC_DAPWDF                     (1 << 6)
+#define CPC_BASSBC                     (1 << 1)
+#define CPC_DEEMPF                     (0x01)
+
+/* Field masks for TSC2101_AUDIO_CTRL_3 */
+#define AC3_DMSVOL(ARG)                        (((ARG) & 0x03) << 14)
+#define AC3_REFFS                      (1 << 13)
+#define AC3_DAXFM                      (1 << 12)
+#define AC3_SLVMS                      (1 << 11)
+#define AC3_DALOVF                     (1 << 7)
+#define AC3_DAROVF                     (1 << 6)
+#define AC3_REVID(ARG)                 (((ARG) & 0x07))
+
+/* Field masks for TSC2102_PLL1_CTRL */
+#define PLL1_PLLEN                     (1 << 15)
+#define PLL1_Q_VAL(ARG)                        (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG)                        (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG)                        (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC2102_PLL2_CTRL */
+#define PLL2_D_VAL(ARG)                        (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC2101_AUDIO_CTRL_4 */
+#define AC4_DASTPD                     (1 << 14)
+
+struct tsc2102_rate_info_s {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44k;      /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC2102_H */
diff --git a/include/linux/spi/tsc210x.h b/include/linux/spi/tsc210x.h
new file mode 100644 (file)
index 0000000..b1a9ae6
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * include/linux/spi/tsc2102.h
+ *
+ * TI TSC2101/2102 control register definitions.
+ *
+ * Copyright (c) 2005-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This package is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this package; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __LINUX_SPI_TSC210X_H
+#define __LINUX_SPI_TSC210X_H
+
+struct apm_power_info;
+
+struct tsc210x_config {
+       int use_internal;       /* Use internal reference voltage */
+       u32 monitor;            /* What inputs are wired on this board */
+       int temp_at25c[2];      /* Thermometer calibration data */
+       void (*apm_report)(struct apm_power_info *info, int battery[]);
+                               /* Report status to APM based on battery[] */
+       void *alsa_config;      /* .platform_data for the ALSA device */
+       const char *mclk;       /* Optional: mclk name */
+       const char *bclk;       /* Optional: bclk name */
+};
+
+#define TSC_BAT1       (1 << 0)
+#define TSC_BAT2       (1 << 1)
+#define TSC_AUX1       (1 << 2)
+#define TSC_AUX2       (1 << 3)
+#define TSC_TEMP       (1 << 4)
+
+#define TSC_AUX                TSC_AUX1
+#define TSC_VBAT       TSC_BAT1
+
+struct tsc210x_dev;
+
+/* Drivers for tsc210x components like touchscreen, sensor, and audio
+ * are packaged as platform drivers which can issue synchronous register
+ * acceses, and may also register a callback to process their particular
+ * type of data when that data is automatically sampled.  The platform
+ * device is a child of the TSC spi device.
+ */
+
+extern int tsc210x_read_sync(struct tsc210x_dev *dev, int page, u8 address);
+extern int tsc210x_reads_sync(struct tsc210x_dev *dev, int page,
+               u8 startaddress, u16 *data, int numregs);
+extern int tsc210x_write_sync(struct tsc210x_dev *dev, int page,
+               u8 address, u16 data);
+
+typedef void (*tsc210x_touch_t)(void *context, int touching);
+typedef void (*tsc210x_coords_t)(void *context, int x, int y, int z1, int z2);
+typedef void (*tsc210x_ports_t)(void *context, int bat[], int aux[]);
+typedef void (*tsc210x_temp_t)(void *context, int temp);
+
+extern int tsc210x_touch_cb(struct device *dev,
+               tsc210x_touch_t handler, void *context);
+extern int tsc210x_coords_cb(struct device *dev,
+               tsc210x_coords_t handler, void *context);
+extern int tsc210x_ports_cb(struct device *dev,
+               tsc210x_ports_t handler, void *context);
+extern int tsc210x_temp1_cb(struct device *dev,
+               tsc210x_temp_t handler, void *context);
+extern int tsc210x_temp2_cb(struct device *dev,
+               tsc210x_temp_t handler, void *context);
+
+#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+extern void tsc210x_set_dac_volume(struct device *dev, u8 left, u8 right);
+extern void tsc210x_set_dac_mute(struct device *dev, int left, int right);
+extern void tsc210x_get_dac_mute(struct device *dev, int *left, int *right);
+extern void tsc210x_dac_power(struct device *dev, int on);
+extern int tsc210x_set_rate(struct device *dev, int rate);
+extern void tsc210x_set_i2s_master(struct device *dev, int state);
+extern void tsc210x_set_deemphasis(struct device *dev, int enable);
+extern void tsc2102_set_bassboost(struct device *dev, int enable);
+#endif
+
+/*
+ * Emit a short keyclick typically in order to give feedback to
+ * user on specific events.
+ *
+ * amplitude must be between 0 (lowest) and 2 (highest).
+ * freq must be between 0 (corresponds to 62.5 Hz) and 7 (8 kHz).
+ * length should be between 2 and 32 periods.
+ *
+ * This function sleeps but for a period unrelated to the length of
+ * the sound, i.e. returning doesn't indicate that the sound has
+ * finished.
+ */
+extern void tsc210x_keyclick(struct tsc210x_dev *dev,
+               int amplitude, int freq, int length);
+
+/* Page 0, Touch Screen & Keypad Data registers */
+#define TSC210X_TS_X                   0, 0x00
+#define TSC210X_TS_Y                   0, 0x01
+#define TSC210X_TS_Z1                  0, 0x02
+#define TSC210X_TS_Z2                  0, 0x03
+#define TSC210X_TS_BAT1                        0, 0x05
+#define TSC2102_TS_BAT2                        0, 0x06
+#define TSC210X_TS_AUX1                        0, 0x07
+#define TSC2101_TS_AUX2                        0, 0x08
+#define TSC210X_TS_TEMP1               0, 0x09
+#define TSC210X_TS_TEMP2               0, 0x0a
+
+/* Page 1, Touch Screen & Keypad Control registers */
+#define TSC210X_TS_ADC_CTRL            1, 0x00
+#define TSC210X_TS_STATUS_CTRL         1, 0x01
+#define TSC2101_TS_BUFFER_CTRL         1, 0x02
+#define TSC210X_TS_REF_CTRL            1, 0x03
+#define TSC210X_TS_RESET_CTRL          1, 0x04
+#define TSC210X_TS_CONFIG_CTRL         1, 0x05
+#define TSC2101_TS_TEMPMAX_CTRL                1, 0x06
+#define TSC2101_TS_TEMPMIN_CTRL                1, 0x07
+#define TSC2101_TS_AUX1MAX_CTRL                1, 0x08
+#define TSC2101_TS_AUX1MIN_CTRL                1, 0x09
+#define TSC2101_TS_AUX2MAX_CTRL                1, 0x0a
+#define TSC2101_TS_AUX2MIN_CTRL                1, 0x0b
+#define TSC2101_TS_MCONFIG_CTRL                1, 0x0c
+#define TSC2101_TS_DELAY_CTRL          1, 0x0d
+
+/* Page 2, Audio Control registers */
+#define TSC210X_AUDIO1_CTRL            2, 0x00
+#define TSC2101_HEADSET_GAIN_CTRL      2, 0x01
+#define TSC210X_DAC_GAIN_CTRL          2, 0x02
+#define TSC2101_MIXER_GAIN_CTRL                2, 0x03
+#define TSC210X_AUDIO2_CTRL            2, 0x04
+#define TSC210X_POWER_CTRL             2, 0x05
+#define TSC210X_AUDIO3_CTRL            2, 0x06
+#define TSC210X_LCH_BASS_BOOST_N0      2, 0x07
+#define TSC210X_LCH_BASS_BOOST_N1      2, 0x08
+#define TSC210X_LCH_BASS_BOOST_N2      2, 0x09
+#define TSC210X_LCH_BASS_BOOST_N3      2, 0x0a
+#define TSC210X_LCH_BASS_BOOST_N4      2, 0x0b
+#define TSC210X_LCH_BASS_BOOST_N5      2, 0x0c
+#define TSC210X_LCH_BASS_BOOST_D1      2, 0x0d
+#define TSC210X_LCH_BASS_BOOST_D2      2, 0x0e
+#define TSC210X_LCH_BASS_BOOST_D4      2, 0x0f
+#define TSC210X_LCH_BASS_BOOST_D5      2, 0x10
+#define TSC210X_RCH_BASS_BOOST_N0      2, 0x11
+#define TSC210X_RCH_BASS_BOOST_N1      2, 0x12
+#define TSC210X_RCH_BASS_BOOST_N2      2, 0x13
+#define TSC210X_RCH_BASS_BOOST_N3      2, 0x14
+#define TSC210X_RCH_BASS_BOOST_N4      2, 0x15
+#define TSC210X_RCH_BASS_BOOST_N5      2, 0x16
+#define TSC210X_RCH_BASS_BOOST_D1      2, 0x17
+#define TSC210X_RCH_BASS_BOOST_D2      2, 0x18
+#define TSC210X_RCH_BASS_BOOST_D4      2, 0x19
+#define TSC210X_RCH_BASS_BOOST_D5      2, 0x1a
+#define TSC210X_PLL1_CTRL              2, 0x1b
+#define TSC210X_PLL2_CTRL              2, 0x1c
+#define TSC210X_AUDIO4_CTRL            2, 0x1d
+#define TSC2101_HANDSET_GAIN_CTRL      2, 0x1e
+#define TSC2101_CELL_GAIN_CTRL         2, 0x1f
+#define TSC2101_AUIDO5_CTRL            2, 0x20
+#define TSC2101_AUDIO6_CTRL            2, 0x21
+#define TSC2101_AUDIO7_CTRL            2, 0x22
+#define TSC2101_GPIO_CTRL              2, 0x23
+#define TSC2101_IN_AGC_CTRL            2, 0x24
+#define TSC2101_POWER_STATUS           2, 0x25
+#define TSC2101_MIX_AGC_CTRL           2, 0x26
+#define TSC2101_CELL_AGC_CTRL          2, 0x27
+
+/* Field masks for Audio Control 1 */
+#define AC1_WLEN(ARG)                  (((ARG) & 0x03) << 10)
+#define AC1_DATFM(ARG)                 (((ARG) & 0x03) << 8)
+#define AC1_DACFS(ARG)                 ((ARG) & 0x3f)
+
+/* Field masks for TSC2102_DAC_GAIN_CTRL */
+#define DGC_DALMU                      (1 << 15)
+#define DGC_DALVL(ARG)                 (((ARG) & 0x7f) << 8)
+#define DGC_DARMU                      (1 << 7)
+#define DGC_DARVL(ARG)                 (((ARG) & 0x7f))
+
+/* Field formats for TSC210X_AUDIO2_CTRL */
+#define AC2_KCLEN                      (1 << 15)
+#define AC2_KCLAC(ARG)                 (((ARG) & 0x07) << 12)
+#define AC2_KCLFRQ(ARG)                        (((ARG) & 0x07) << 8)
+#define AC2_KCLLN(ARG)                 (((ARG) & 0x0f) << 4)
+#define AC2_DLGAF                      (1 << 3)
+#define AC2_DRGAF                      (1 << 2)
+#define AC2_DASTC                      (1 << 1)
+
+/* Field masks for TSC210X_DAC_POWER_CTRL */
+#define CPC_PWDNC                      (1 << 15)
+#define CPC_DAODRC                     (1 << 12)
+#define CPC_DAPWDN                     (1 << 10)
+#define CPC_VGPWDN                     (1 << 8)
+#define CPC_DAPWDF                     (1 << 6)
+#define CPC_BASSBC                     (1 << 1)
+#define CPC_DEEMPF                     (0x01)
+
+/* Field masks for TSC210X_AUDIO3_CTRL */
+#define AC3_DMSVOL(ARG)                        (((ARG) & 0x03) << 14)
+#define AC3_REFFS                      (1 << 13)
+#define AC3_DAXFM                      (1 << 12)
+#define AC3_SLVMS                      (1 << 11)
+#define AC3_DALOVF                     (1 << 7)
+#define AC3_DAROVF                     (1 << 6)
+#define AC3_REVID(ARG)                 (((ARG) & 0x07))
+
+/* Field masks for TSC210X_PLL1_CTRL */
+#define PLL1_PLLEN                     (1 << 15)
+#define PLL1_Q_VAL(ARG)                        (((ARG) & 0x0f) << 11)
+#define PLL1_P_VAL(ARG)                        (((ARG) & 0x07) << 8)
+#define PLL1_I_VAL(ARG)                        (((ARG) & 0x3f) << 2)
+
+/* Field masks for TSC210X_PLL2_CTRL */
+#define PLL2_D_VAL(ARG)                        (((ARG) & 0x3fff) << 2)
+
+/* Field masks for TSC210X_AUDIO4_CTRL */
+#define AC4_DASTPD                     (1 << 14)
+
+struct tsc210x_rate_info_s {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44k;      /* 44.1 kHz Fsref if 1, 48 kHz if 0 */
+};
+
+#endif /* __LINUX_SPI_TSC210X_H */
diff --git a/include/linux/spi/tsc2301.h b/include/linux/spi/tsc2301.h
new file mode 100644 (file)
index 0000000..4552eba
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef _LINUX_SPI_TSC2301_H
+#define _LINUX_SPI_TSC2301_H
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+struct tsc2301_platform_data {
+       /*
+        * Keypad
+        */
+       s16     reset_gpio;
+       s16     keyb_int;
+       s16     keymap[16];     /* Set a key to a negative value if not used */
+       unsigned kp_rep:1;      /* Enable keypad repeating */
+       char    *keyb_name;     /* Keyboard device name */
+
+       /*
+        * Touchscreen
+        */
+       s16     dav_int;
+       u16     ts_x_plate_ohm;
+       u32     ts_stab_time;   /* voltage settling time */
+       u8      ts_hw_avg;      /* HW assiseted averaging. Can be
+                                  0, 4, 8, 16 samples per reading */
+       u32     ts_max_pressure;/* Samples with bigger pressure value will
+                                  be ignored, since the corresponding X, Y
+                                  values are unreliable */
+       u32     ts_touch_pressure;      /* Pressure limit until we report a
+                                          touch event. After that we switch
+                                          to ts_max_pressure. */
+       u32     ts_pressure_fudge;
+       u32     ts_x_max;
+       u32     ts_x_fudge;
+       u32     ts_y_max;
+       u32     ts_y_fudge;
+
+       /*
+        * Audio
+        */
+       unsigned        pll_pdc:4;
+       unsigned        pll_a:4;
+       unsigned        pll_n:4;
+       unsigned        pll_output:1; /* Output PLL on GPIO_0 */
+
+       unsigned        mclk_ratio:2;
+       unsigned        i2s_sample_rate:4;
+       unsigned        i2s_format:2;
+       /* Mask for audio blocks to be powered down */
+       u16             power_down_blocks;
+
+       /* Called after codec has been initialized, can be NULL */
+       int (* codec_init)(struct device *tsc2301_dev);
+       /* Called when codec is being removed, can be NULL */
+       void (* codec_cleanup)(struct device *tsc2301_dev);
+       int     (*enable_clock)(struct device *dev);
+       void    (*disable_clock)(struct device *dev);
+
+       const struct tsc2301_mixer_gpio {
+               const char      *name;
+               unsigned        gpio:4;
+               unsigned        inverted:1;
+               unsigned        def_enable:1; /* enable by default */
+               unsigned        deactivate_on_pd:1; /* power-down flag */
+       } *mixer_gpios;
+       int     n_mixer_gpios;
+};
+
+struct tsc2301_kp;
+struct tsc2301_ts;
+struct tsc2301_mixer;
+
+struct tsc2301 {
+       struct spi_device       *spi;
+
+       s16                     reset_gpio;
+       u16                     config2_shadow;
+
+        struct tsc2301_kp      *kp;
+       struct tsc2301_ts       *ts;
+       struct tsc2301_mixer    *mixer;
+
+       int                     (*enable_clock)(struct device *dev);
+       void                    (*disable_clock)(struct device *dev);
+};
+
+
+#define TSC2301_HZ     33000000
+
+#define TSC2301_REG(page, addr)  (((page) << 11) | ((addr) << 5))
+#define TSC2301_REG_TO_PAGE(reg) (((reg) >> 11) & 0x03)
+#define TSC2301_REG_TO_ADDR(reg) (((reg) >> 5)  & 0x1f)
+
+#define TSC2301_REG_X          TSC2301_REG(0, 0)
+#define TSC2301_REG_Y          TSC2301_REG(0, 1)
+#define TSC2301_REG_Z1         TSC2301_REG(0, 2)
+#define TSC2301_REG_Z2         TSC2301_REG(0, 3)
+#define TSC2301_REG_KPDATA     TSC2301_REG(0, 4)
+#define TSC2301_REG_ADC                TSC2301_REG(1, 0)
+#define TSC2301_REG_KEY                TSC2301_REG(1, 1)
+#define TSC2301_REG_DAC                TSC2301_REG(1, 2)
+#define TSC2301_REG_REF                TSC2301_REG(1, 3)
+#define TSC2301_REG_RESET      TSC2301_REG(1, 4)
+#define TSC2301_REG_CONFIG     TSC2301_REG(1, 5)
+#define TSC2301_REG_CONFIG2    TSC2301_REG(1, 6)
+#define TSC2301_REG_KPMASK     TSC2301_REG(1, 16)
+#define TSC2301_REG_AUDCNTL    TSC2301_REG(2, 0)
+#define TSC2301_REG_ADCVOL     TSC2301_REG(2, 1)
+#define TSC2301_REG_DACVOL     TSC2301_REG(2, 2)
+#define TSC2301_REG_BPVOL      TSC2301_REG(2, 3)
+#define TSC2301_REG_KEYCTL     TSC2301_REG(2, 4)
+#define TSC2301_REG_PD_MISC    TSC2301_REG(2, 5)
+#define TSC2301_REG_GPIO       TSC2301_REG(2, 6)
+#define TSC2301_REG_ADCLKCFG   TSC2301_REG(2, 27)
+
+#define TSC2301_REG_PD_MISC_APD                (1 << 15)
+#define TSC2301_REG_PD_MISC_AVPD       (1 << 14)
+#define TSC2301_REG_PD_MISC_ABPD       (1 << 13)
+#define TSC2301_REG_PD_MISC_HAPD       (1 << 12)
+#define TSC2301_REG_PD_MISC_MOPD       (1 << 11)
+#define TSC2301_REG_PD_MISC_DAPD       (1 << 10)
+#define TSC2301_REG_PD_MISC_ADPDL      (1 << 9)
+#define TSC2301_REG_PD_MISC_ADPDR      (1 << 8)
+#define TSC2301_REG_PD_MISC_PDSTS      (1 << 7)
+#define TSC2301_REG_PD_MISC_MIBPD      (1 << 6)
+#define TSC2301_REG_PD_MISC_OTSYN      (1 << 2)
+
+/* I2S sample rate */
+#define TSC2301_I2S_SR_48000   0x00
+#define TSC2301_I2S_SR_44100   0x01
+#define TSC2301_I2S_SR_32000   0x02
+#define TSC2301_I2S_SR_24000   0x03
+#define TSC2301_I2S_SR_22050   0x04
+#define TSC2301_I2S_SR_16000   0x05
+#define TSC2301_I2S_SR_12000   0x06
+#define TSC2301_I2S_SR_11050   0x07
+#define TSC2301_I2S_SR_8000    0x08
+
+/* 16-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT0    0x00
+/* 20-bit, MSB-first. DAC Right-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT1    0x01
+/* 20-bit, MSB-first. DAC Left-Justified, ADC Left-Justified */
+#define TSC2301_I2S_FORMAT2    0x02
+/* 20-bit, MSB-first */
+#define TSC2301_I2S_FORMAT3    0x03
+
+/* Master Clock Ratio */
+#define TSC2301_MCLK_256xFS    0x00 /* default */
+#define TSC2301_MCLK_384xFS    0x01
+#define TSC2301_MCLK_512xFS    0x02
+
+
+extern u16 tsc2301_read_reg(struct tsc2301 *tsc, int reg);
+extern void tsc2301_write_reg(struct tsc2301 *tsc, int reg, u16 val);
+extern void tsc2301_write_kbc(struct tsc2301 *tsc, int val);
+extern void tsc2301_write_pll(struct tsc2301 *tsc, int pll_n, int pll_a,
+                             int pll_pdc, int pct_e, int pll_o);
+extern void tsc2301_read_buf(struct tsc2301 *tsc, int reg, u16 *buf, int len);
+
+#define TSC2301_DECL_MOD(module)                                       \
+extern int  tsc2301_##module##_init(struct tsc2301 *tsc,               \
+                          struct tsc2301_platform_data *pdata);        \
+extern void tsc2301_##module##_exit(struct tsc2301 *tsc);              \
+extern int  tsc2301_##module##_suspend(struct tsc2301 *tsc);           \
+extern void tsc2301_##module##_resume(struct tsc2301 *tsc);
+
+#define TSC2301_DECL_EMPTY_MOD(module)                                 \
+static inline int tsc2301_##module##_init(struct tsc2301 *tsc,         \
+                          struct tsc2301_platform_data *pdata)         \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_exit(struct tsc2301 *tsc) {}     \
+static inline int  tsc2301_##module##_suspend(struct tsc2301 *tsc)     \
+{                                                                      \
+       return 0;                                                       \
+}                                                                      \
+static inline void tsc2301_##module##_resume(struct tsc2301 *tsc) {}
+
+#ifdef CONFIG_KEYBOARD_TSC2301
+TSC2301_DECL_MOD(kp)
+void tsc2301_kp_restart(struct tsc2301 *tsc);
+#else
+TSC2301_DECL_EMPTY_MOD(kp)
+static inline void tsc2301_kp_restart(struct tsc2301 *tsc) {}
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2301
+TSC2301_DECL_MOD(ts)
+#else
+TSC2301_DECL_EMPTY_MOD(ts)
+#endif
+
+#ifdef CONFIG_SPI_TSC2301_AUDIO
+TSC2301_DECL_MOD(mixer)
+extern void tsc2301_mixer_set_power(struct device *tsc_dev, int dac, int adc);
+
+struct snd_card;
+extern int tsc2301_mixer_register_controls(struct device *tsc_dev,
+                                          struct snd_card *card);
+#else
+TSC2301_DECL_EMPTY_MOD(mixer)
+#endif
+
+extern void tsc2301_mixer_enable_mclk(struct device *tsc_dev);
+extern void tsc2301_mixer_disable_mclk(struct device *tsc_dev);
+
+#endif
index bc41ad0f24f881845d96d77a00a3d3535968566b..6d3e9999cf763e54e3b27665f7ab086053952771 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/kfifo.h>
 #include <linux/log2.h>
+#include <linux/uaccess.h>
 
 /**
  * kfifo_init - allocates a new FIFO using a preallocated buffer
@@ -195,3 +196,59 @@ unsigned int __kfifo_get(struct kfifo *fifo,
        return len;
 }
 EXPORT_SYMBOL(__kfifo_get);
+
+/**
+ * __kfifo_get_to_user - gets some data from the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ * @buffer: where the data must be copied. user buffer.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * user @buffer and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int __kfifo_get_to_user(struct kfifo *fifo,
+                                unsigned char __user *buffer,
+                                unsigned int len)
+{
+       unsigned int n1, n2;
+       int ret;
+
+       len = min(len, fifo->in - fifo->out);
+
+       /*
+        * Ensure that we sample the fifo->in index -before- we
+        * start removing bytes from the kfifo.
+        */
+
+       smp_rmb();
+
+       /* first get the data from fifo->out until the end of the buffer */
+       n1 = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
+       n2 = len -n1;
+       ret = copy_to_user(buffer,
+                          fifo->buffer + (fifo->out & (fifo->size - 1)), n1);
+       if (ret) {
+               len = n1 - ret;
+               goto out;
+       }
+
+       /* then get the rest (if any) from the beginning of the buffer */
+       ret = copy_to_user(buffer + n1, fifo->buffer, n2);
+       if (ret)
+               len = n1 + n2 - ret;
+
+       /*
+        * Ensure that we remove the bytes from the kfifo -before-
+        * we update the fifo->out index.
+        */
+out:
+       smp_mb();
+
+       fifo->out += len;
+
+       return len;
+}
+EXPORT_SYMBOL(__kfifo_get_to_user);
index b51b1567bb5570dfc5b4a19bffd5af865d254e77..8b223afafe63bebc6ca1bde9ba23e89b436db97a 100644 (file)
@@ -44,6 +44,10 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
 
 #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 */
 
@@ -708,6 +712,9 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        printed_len += vscnprintf(printk_buf + printed_len,
                                  sizeof(printk_buf) - printed_len, fmt, args);
 
+#ifdef CONFIG_DEBUG_LL
+       printascii(printk_buf);
+#endif
 
        /*
         * Copy the output into log_buf.  If the caller didn't provide
index 90eb7cb47e7723fb57e035e447e3ff182dd46d77..37e44705ff9dca3125db27e942133931c253ca9e 100644 (file)
@@ -215,6 +215,19 @@ config IP_NF_TARGET_NETMAP
          addresses. It maps the network address part, while keeping the host
          address part intact.
 
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config IP_NF_TARGET_IDLETIMER
+       tristate  "IDLETIMER target support"
+       depends on IP_NF_IPTABLES
+       help
+         This option adds a `IDLETIMER' target. Each matching packet resets
+         the timer associated with input and/or output interfaces. Timer
+         expiry causes kobject uevent. Idle timer can be read via sysfs.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+
          To compile it as a module, choose M here.  If unsure, say N.
 
 config NF_NAT_SNMP_BASIC
index 3f31291f37ce7c6c68513eb269ccb87de09b3dac..927ddabaffb2849e0330dfd553421446b37a7bb8 100644 (file)
@@ -59,6 +59,7 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+obj-$(CONFIG_IP_NF_TARGET_IDLETIMER) += ipt_IDLETIMER.o
 obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 
diff --git a/net/ipv4/netfilter/ipt_IDLETIMER.c b/net/ipv4/netfilter/ipt_IDLETIMER.c
new file mode 100644 (file)
index 0000000..6432192
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * linux/net/ipv4/netfilter/ipt_IDLETIMER.c
+ *
+ * Netfilter module to trigger a timer when packet matches.
+ * After timer expires a kevent will be sent.
+ *
+ * Copyright (C) 2004 Nokia Corporation. All rights reserved.
+ * Written by Timo Teras <ext-timo.teras@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/netfilter.h>
+#include <linux/rtnetlink.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ipt_IDLETIMER.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+
+#if 0
+#define DEBUGP(format, args...) printk("%s:%s:" format, \
+                                       __FILE__, __FUNCTION__ , ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/*
+ * Internal timer management.
+ */
+static ssize_t utimer_attr_show(struct device *, struct device_attribute *attr, char *buf);
+static ssize_t utimer_attr_store(struct device *, struct device_attribute *attr,
+                                const char *buf, size_t count);
+
+struct utimer_t {
+       char name[IFNAMSIZ];
+       struct list_head entry;
+       struct timer_list timer;
+       struct work_struct work;
+};
+
+static LIST_HEAD(active_utimer_head);
+static DEFINE_SPINLOCK(list_lock);
+static DEVICE_ATTR(idletimer, 0644, utimer_attr_show, utimer_attr_store);
+
+static void utimer_delete(struct utimer_t *timer)
+{
+       DEBUGP("Deleting timer '%s'\n", timer->name);
+
+       list_del(&timer->entry);
+       del_timer_sync(&timer->timer);
+       kfree(timer);
+}
+
+static void utimer_work(struct work_struct *work)
+{
+       struct utimer_t *timer = container_of(work, struct utimer_t, work);
+       struct net_device *netdev;
+
+       netdev = dev_get_by_name(&init_net, timer->name);
+
+       if (netdev != NULL) {
+               sysfs_notify(&netdev->dev.kobj, NULL,
+                            "idletimer");
+               dev_put(netdev);
+       }
+}
+
+static void utimer_expired(unsigned long data)
+{
+       struct utimer_t *timer = (struct utimer_t *) data;
+
+       DEBUGP("Timer '%s' expired\n", timer->name);
+
+       spin_lock_bh(&list_lock);
+       utimer_delete(timer);
+       spin_unlock_bh(&list_lock);
+
+       schedule_work(&timer->work);
+}
+
+static struct utimer_t *utimer_create(const char *name)
+{
+       struct utimer_t *timer;
+
+       timer = kmalloc(sizeof(struct utimer_t), GFP_ATOMIC);
+       if (timer == NULL)
+               return NULL;
+
+       list_add(&timer->entry, &active_utimer_head);
+       strlcpy(timer->name, name, sizeof(timer->name));
+
+       init_timer(&timer->timer);
+       timer->timer.function = utimer_expired;
+       timer->timer.data = (unsigned long) timer;
+
+       INIT_WORK(&timer->work, utimer_work);
+
+       DEBUGP("Created timer '%s'\n", timer->name);
+
+       return timer;
+}
+
+static struct utimer_t *__utimer_find(const char *name)
+{
+       struct utimer_t *entry;
+
+       list_for_each_entry(entry, &active_utimer_head, entry) {
+               if (strcmp(name, entry->name) == 0) {
+                       return entry;
+               }
+       }
+
+       return NULL;
+}
+
+static void utimer_modify(const char *name,
+                         unsigned long expires)
+{
+       struct utimer_t *timer;
+
+       DEBUGP("Modifying timer '%s'\n", name);
+       spin_lock_bh(&list_lock);
+       timer = __utimer_find(name);
+       if (timer == NULL)
+               timer = utimer_create(name);
+       mod_timer(&timer->timer, expires);
+       spin_unlock_bh(&list_lock);
+}
+
+static ssize_t utimer_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct utimer_t *timer;
+       unsigned long expires = 0;
+       struct net_device *netdev = container_of(dev, struct net_device, dev);
+
+       spin_lock_bh(&list_lock);
+       timer = __utimer_find(netdev->name);
+       if (timer)
+               expires = timer->timer.expires;
+       spin_unlock_bh(&list_lock);
+
+       if (expires)
+               return sprintf(buf, "%lu\n", (expires-jiffies) / HZ);
+
+       return sprintf(buf, "0\n");
+}
+
+static ssize_t utimer_attr_store(struct device *dev, struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       int expires;
+       struct net_device *netdev = container_of(dev, struct net_device, dev);
+
+       if (sscanf(buf, "%d", &expires) == 1) {
+               if (expires > 0)
+                       utimer_modify(netdev->name,
+                                     jiffies+HZ*(unsigned long)expires);
+       }
+
+       return count;
+}
+
+static int utimer_notifier_call(struct notifier_block *this,
+                               unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+       int ret = NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UP:
+               DEBUGP("NETDEV_UP: %s\n", dev->name);
+               ret = device_create_file(&dev->dev,
+                                        &dev_attr_idletimer);
+               break;
+       case NETDEV_DOWN:
+               DEBUGP("NETDEV_DOWN: %s\n", dev->name);
+               device_remove_file(&dev->dev,
+                                        &dev_attr_idletimer);
+               break;
+       }
+
+       return ret;
+}
+
+static struct notifier_block utimer_notifier_block = {
+       .notifier_call  = utimer_notifier_call,
+};
+
+
+static int utimer_init(void)
+{
+        return register_netdevice_notifier(&utimer_notifier_block);
+}
+
+static void utimer_fini(void)
+{
+       struct utimer_t *entry, *next;
+       struct net_device *dev;
+
+       list_for_each_entry_safe(entry, next, &active_utimer_head, entry)
+               utimer_delete(entry);
+
+       rtnl_lock();
+       unregister_netdevice_notifier(&utimer_notifier_block);
+       for_each_netdev(&init_net, dev)
+               utimer_notifier_call(&utimer_notifier_block,
+                                    NETDEV_DOWN, dev);
+       rtnl_unlock();
+}
+
+/*
+ * The actual iptables plugin.
+ */
+static unsigned int ipt_idletimer_target(struct sk_buff *pskb,
+                                        const struct net_device *in,
+                                        const struct net_device *out,
+                                        unsigned int hooknum,
+                                        const struct xt_target *xttarget,
+                                        const void *targinfo)
+{
+       struct ipt_idletimer_info *target = (struct ipt_idletimer_info*) targinfo;
+       unsigned long expires;
+
+       expires = jiffies + HZ*target->timeout;
+
+       if (in != NULL)
+               utimer_modify(in->name, expires);
+
+       if (out != NULL)
+               utimer_modify(out->name, expires);
+
+       return XT_CONTINUE;
+}
+
+static bool ipt_idletimer_checkentry(const char *tablename,
+                                   const void *e,
+                                   const struct xt_target *target,
+                                   void *targinfo,
+                                   unsigned int hookmask)
+{
+       struct ipt_idletimer_info *info =
+               (struct ipt_idletimer_info *) targinfo;
+
+       if (info->timeout == 0) {
+               DEBUGP("timeout value is zero\n");
+               return 0;
+       }
+
+       return true;
+}
+
+static struct xt_target ipt_idletimer = {
+       .name           = "IDLETIMER",
+       .target         = ipt_idletimer_target,
+       .checkentry     = ipt_idletimer_checkentry,
+       .me             = THIS_MODULE,
+       .targetsize     = sizeof(struct ipt_idletimer_info),
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = utimer_init();
+       if (ret)
+               return ret;
+
+       if (xt_register_target(&ipt_idletimer)) {
+               utimer_fini();
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(&ipt_idletimer);
+       utimer_fini();
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("Timo Teras <ext-timo.teras@nokia.com>");
+MODULE_DESCRIPTION("iptables idletimer target module");
+MODULE_LICENSE("GPL");
index 559293922a479eabf188b70e963d5264f9032799..811f00270546ce972a10701543edd11024deae59 100644 (file)
@@ -95,6 +95,14 @@ config SECURITY_ROOTPLUG
          
          If you are unsure how to answer this question, answer N.
 
+config SECURITY_LOWMEM
+       tristate "Low memory watermark support"
+       depends on SECURITY
+       help
+         Implements low memory watermark support
+
+         If you are unsure how to answer this question, answer N.
+
 config SECURITY_DEFAULT_MMAP_MIN_ADDR
         int "Low address space to protect from user allocation"
         depends on SECURITY
index f65426099aa625be9aac60a1a009ea860956dbb7..22f845620580dfc7c2a5f3076c8305592f0ffbbe 100644 (file)
@@ -15,4 +15,5 @@ obj-$(CONFIG_SECURITY)                        += security.o capability.o inode.o
 obj-$(CONFIG_SECURITY_SELINUX)         += selinux/built-in.o
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)                += root_plug.o
+obj-$(CONFIG_SECURITY_LOWMEM)          += commoncap.o lowmem.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
diff --git a/security/lowmem.c b/security/lowmem.c
new file mode 100644 (file)
index 0000000..ae78a53
--- /dev/null
@@ -0,0 +1,384 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/sysctl.h>
+#include <linux/swap.h>
+#include <linux/kobject.h>
+#include <linux/pagemap.h>
+#include <linux/hugetlb.h>
+#include <linux/sysfs.h>
+#include <linux/oom.h>
+
+#define MY_NAME "lowmem"
+
+#define LOWMEM_MAX_UIDS 8
+
+enum {
+       VM_LOWMEM_DENY_PAGES = 1,
+       VM_LOWMEM_NOTIFY_LOW_PAGES,
+       VM_LOWMEM_NOTIFY_HIGH_PAGES,
+       VM_LOWMEM_NR_DECAY_PAGES,
+       VM_LOWMEM_ALLOWED_UIDS,
+       VM_LOWMEM_ALLOWED_PAGES,
+       VM_LOWMEM_FREE_PAGES,
+       VM_LOWMEM_DENY,
+       VM_LOWMEM_LEVEL1_NOTIFY,
+       VM_LOWMEM_LEVEL2_NOTIFY,
+       VM_LOWMEM_USED_PAGES
+};
+
+static long deny_pages;
+static long notify_low_pages, notify_high_pages;
+static unsigned int nr_decay_pages;
+static unsigned long allowed_pages;
+static unsigned long lowmem_free_pages;
+static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
+static unsigned int minuid = 1;
+static unsigned int maxuid = 65535;
+static unsigned int deny_percentage;
+static unsigned int l1_notify, l2_notify;
+static long used_pages;
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos);
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos);
+
+static ctl_table lowmem_table[] = {
+       {
+               .ctl_name = VM_LOWMEM_DENY_PAGES,
+               .procname = "lowmem_deny_watermark_pages",
+               .data = &deny_pages,
+               .maxlen = sizeof(long),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_DENY,
+               .procname = "lowmem_deny_watermark",
+               .data = &deny_percentage,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_deny,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
+               .procname = "lowmem_notify_low",
+               .data = &l1_notify,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_l1_notify,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
+               .procname = "lowmem_notify_high",
+               .data = &l2_notify,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_l2_notify,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_USED_PAGES,
+               .procname = "lowmem_used_pages",
+               .data = &used_pages,
+               .maxlen = sizeof(long),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_used,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_NOTIFY_LOW_PAGES,
+               .procname = "lowmem_notify_low_pages",
+               .data = &notify_low_pages,
+               .maxlen = sizeof(long),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_NOTIFY_HIGH_PAGES,
+               .procname = "lowmem_notify_high_pages",
+               .data = &notify_high_pages,
+               .maxlen = sizeof(long),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_NR_DECAY_PAGES,
+               .procname = "lowmem_nr_decay_pages",
+               .data = &nr_decay_pages,
+               .maxlen = sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_ALLOWED_UIDS,
+               .procname = "lowmem_allowed_uids",
+               .data = &allowed_uids,
+               .maxlen = LOWMEM_MAX_UIDS * sizeof(unsigned int),
+               .mode = 0644,
+               .child = NULL,
+               .proc_handler = &proc_dointvec_minmax,
+               .strategy = &sysctl_intvec,
+               .extra1 = &minuid,
+               .extra2 = &maxuid,
+       }, {
+               .ctl_name = VM_LOWMEM_ALLOWED_PAGES,
+               .procname = "lowmem_allowed_pages",
+               .data = &allowed_pages,
+               .maxlen = sizeof(unsigned long),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = VM_LOWMEM_FREE_PAGES,
+               .procname = "lowmem_free_pages",
+               .data = &lowmem_free_pages,
+               .maxlen = sizeof(unsigned long),
+               .mode = 0444,
+               .child = NULL,
+               .proc_handler = &proc_dointvec,
+               .strategy = &sysctl_intvec,
+       }, {
+               .ctl_name = 0
+       }
+};
+
+static ctl_table lowmem_root_table[] = {
+       {
+               .ctl_name = CTL_VM,
+               .procname = "vm",
+               .mode = 0555,
+               .child = lowmem_table,
+       }, {
+               .ctl_name = 0
+       }
+};
+
+#define KERNEL_ATTR_RO(_name) \
+static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
+
+static int low_watermark_reached, high_watermark_reached;
+
+static int
+proc_dointvec_l1_notify(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       l1_notify =
+       100 - (100 * notify_low_pages + allowed_pages / 2) / allowed_pages;
+       return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_l2_notify(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       l2_notify =
+       100 - (100 * notify_high_pages + allowed_pages / 2) / allowed_pages;
+       return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_deny(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       deny_percentage =
+       100 - (100 * deny_pages + allowed_pages / 2) / allowed_pages;
+       return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static int
+proc_dointvec_used(ctl_table *table, int write, struct file *filp,
+                       void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       if (lowmem_free_pages > 0 && allowed_pages > lowmem_free_pages)
+               used_pages = allowed_pages - lowmem_free_pages;
+       else
+               used_pages = 0;
+       return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+}
+
+static ssize_t low_watermark_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%u\n", low_watermark_reached);
+}
+
+static ssize_t high_watermark_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *page)
+{
+       return sprintf(page, "%u\n", high_watermark_reached);
+}
+
+KERNEL_ATTR_RO(low_watermark);
+KERNEL_ATTR_RO(high_watermark);
+
+static void low_watermark_state(int new_state)
+{
+       if (low_watermark_reached != new_state) {
+               low_watermark_reached = new_state;
+               sysfs_notify(kernel_kobj, NULL, "low_watermark");
+       }
+}
+
+static void high_watermark_state(int new_state)
+{
+       if (high_watermark_reached != new_state) {
+               high_watermark_reached = new_state;
+               sysfs_notify(kernel_kobj, NULL, "high_watermark");
+       }
+}
+
+static int low_vm_enough_memory(struct mm_struct *mm, long pages)
+{
+       unsigned long free, allowed;
+       int cap_sys_admin = 0, notify;
+
+       if (cap_capable(current, CAP_SYS_ADMIN) == 0)
+               cap_sys_admin = 1;
+
+       allowed = totalram_pages - hugetlb_total_pages();
+       allowed_pages = allowed;
+
+       /* We activate ourselves only after both parameters have been
+        * configured. */
+       if (deny_pages == 0 || notify_low_pages == 0 || notify_high_pages == 0)
+               return  __vm_enough_memory(mm, pages, cap_sys_admin);
+
+       vm_acct_memory(pages);
+
+       /* Easily freed pages when under VM pressure or direct reclaim */
+       free = global_page_state(NR_FILE_PAGES);
+       free += nr_swap_pages;
+       free += global_page_state(NR_SLAB_RECLAIMABLE);
+
+       if (likely(free > notify_low_pages))
+               goto enough_memory;
+
+       /* No luck, lets make it more expensive and try again.. */
+       free += nr_free_pages();
+
+       if (free < deny_pages) {
+               int i;
+
+               lowmem_free_pages = free;
+               low_watermark_state(1);
+               high_watermark_state(1);
+               /* Memory allocations by root are always allowed */
+               if (cap_sys_admin)
+                       return 0;
+
+               /* OOM unkillable process is allowed to consume memory */
+               if (current->oomkilladj == OOM_DISABLE)
+                       return 0;
+
+               /* uids from allowed_uids vector are also allowed no matter what */
+               for (i = 0; i < LOWMEM_MAX_UIDS && allowed_uids[i]; i++)
+                       if (current->uid == allowed_uids[i])
+                               return 0;
+
+               vm_unacct_memory(pages);
+               if (printk_ratelimit()) {
+                       printk(MY_NAME ": denying memory allocation to process %d (%s)\n",
+                              current->pid, current->comm);
+               }
+               return -ENOMEM;
+       }
+
+enough_memory:
+       /* See if we need to notify level 1 */
+       low_watermark_state(free < notify_low_pages);
+
+       /*
+        * In the level 2 notification case things are more complicated,
+        * as the level that we drop the state and send a notification
+        * should be lower than when it is first triggered. Having this
+        * on the same watermark level ends up bouncing back and forth
+        * when applications are being stupid.
+        */
+       notify = free < notify_high_pages;
+       if (notify || free - nr_decay_pages > notify_high_pages)
+               high_watermark_state(notify);
+
+       /* We have plenty of memory */
+       lowmem_free_pages = free;
+       return 0;
+}
+
+static struct security_operations lowmem_security_ops = {
+       /* Use the capability functions for some of the hooks */
+       .ptrace_may_access = cap_ptrace_may_access,
+       .ptrace_traceme = cap_ptrace_traceme,
+       .capget = cap_capget,
+       .capset_check = cap_capset_check,
+       .capset_set = cap_capset_set,
+       .capable = cap_capable,
+
+       .bprm_apply_creds = cap_bprm_apply_creds,
+       .bprm_set_security = cap_bprm_set_security,
+
+       .task_post_setuid = cap_task_post_setuid,
+       .task_reparent_to_init = cap_task_reparent_to_init,
+       .vm_enough_memory = low_vm_enough_memory,
+};
+
+static struct ctl_table_header *lowmem_table_header;
+
+static struct attribute *lowmem_attrs[] = {
+       &low_watermark_attr.attr,
+       &high_watermark_attr.attr,
+       NULL,
+};
+
+static struct attribute_group lowmem_attr_group = {
+       .attrs  = lowmem_attrs,
+};
+
+static int __init lowmem_init(void)
+{
+       int r;
+
+       /* register ourselves with the security framework */
+       if (register_security(&lowmem_security_ops)) {
+               printk(KERN_ERR MY_NAME ": Failure registering with the kernel\n");
+               return -EINVAL;
+       }
+
+       /* initialize the uids vector */
+       memset(allowed_uids, 0, sizeof(allowed_uids));
+
+       lowmem_table_header = register_sysctl_table(lowmem_root_table);
+       if (unlikely(!lowmem_table_header))
+               return -EPERM;
+
+       r = sysfs_create_group(kernel_kobj,
+                              &lowmem_attr_group);
+       if (unlikely(r))
+               return r;
+
+       printk(KERN_INFO MY_NAME ": Module initialized.\n");
+
+       return 0;
+}
+
+module_init(lowmem_init);
+
+MODULE_DESCRIPTION("Low watermark LSM module");
+MODULE_LICENSE("GPL");
index 351e19ea3785ce7159fe6957abc97a1b1c963971..06a24df059f8d1e166bb92a81d165c7ae6a002a3 100644 (file)
@@ -41,5 +41,68 @@ config SND_PXA2XX_AC97
          Say Y or M if you want to support any AC97 codec attached to
          the PXA2xx AC97 interface.
 
-endif  # SND_ARM
+config SND_OMAP_AIC23
+       tristate "OMAP AIC23 alsa driver (osk5912)"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select I2C
+       select I2C_OMAP if ARCH_OMAP
+       select SENSORS_TLV320AIC23
+       help
+         Say Y here if you have a OSK platform board
+         and want to use its AIC23 audio chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-aic23.
+         
+config SND_OMAP_TSC2101
+       tristate "OMAP TSC2101 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+         select SPI_TSC2101
+       help
+         Say Y here if you have a OMAP platform board
+         and want to use its TSC2101 audio chip. Driver has
+         been tested with H2 and iPAQ h6300.
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2101.
+
+config SND_SX1
+       tristate "Siemens SX1 Egold alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       help
+         Say Y here if you have a OMAP310 based Siemens SX1.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-sx1.
+
+config SND_OMAP_TSC2102
+       tristate "OMAP TSC2102 alsa driver"
+       depends on ARCH_OMAP && SND
+       select SND_PCM
+       select SPI_TSC2102
+       help
+         Say Y here if you have an OMAP platform board
+         and want to use its TSC2102 audio chip.
 
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap-tsc2102.
+
+config SND_OMAP24XX_EAC
+       tristate "Audio driver for OMAP24xx EAC"
+       depends on SND
+       help
+         Audio driver for Enhanced Audio Controller found in TI's OMAP24xx
+         processors.
+
+         Currently contains only low-level support functions for
+         initializing EAC HW, creating ALSA sound card instance for it
+         and registering mixer controls implemented by a codec driver.
+         PCM stream is expected to be under DSP co-processor control.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-omap24xx-eac.
+
+endif  # SND_ARM
index 4ef6dd00c6eeafb9916378ad7098b642a309a0cc..bd12f53404a6c1c975db9754381bdc14096c532c 100644 (file)
@@ -13,3 +13,5 @@ snd-pxa2xx-pcm-objs           := pxa2xx-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_AC97)  += snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs           := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND) += omap/
diff --git a/sound/arm/omap/Makefile b/sound/arm/omap/Makefile
new file mode 100644 (file)
index 0000000..2f004d7
--- /dev/null
@@ -0,0 +1,18 @@
+#
+## Makefile for ALSA OMAP
+#
+#
+obj-$(CONFIG_SND_OMAP_AIC23) += snd-omap-alsa-aic23.o
+snd-omap-alsa-aic23-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-aic23.o omap-alsa-aic23-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2101) += snd-omap-alsa-tsc2101.o
+snd-omap-alsa-tsc2101-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2101.o omap-alsa-tsc2101-mixer.o
+
+obj-$(CONFIG_SND_OMAP_TSC2102) += snd-omap-alsa-tsc2102.o
+snd-omap-alsa-tsc2102-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-tsc2102.o omap-alsa-tsc2102-mixer.o
+
+obj-$(CONFIG_SND_SX1) += snd-omap-alsa-sx1.o
+snd-omap-alsa-sx1-objs := omap-alsa.o omap-alsa-dma.o omap-alsa-sx1.o omap-alsa-sx1-mixer.o
+
+obj-$(CONFIG_SND_OMAP24XX_EAC) += snd-omap24xx-eac.o
+snd-omap24xx-eac-objs := eac.o
diff --git a/sound/arm/omap/eac.c b/sound/arm/omap/eac.c
new file mode 100644 (file)
index 0000000..667051e
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * linux/sound/arm/omap/omap-alsa-eac.c
+ *
+ * OMAP24xx Enhanced Audio Controller sound driver
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
+ *          Juha Yrjölä
+ *
+ * Definitions:
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <mach/eac.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+
+#define EAC_CPCFR1             0x0000
+#define EAC_CPCFR2             0x0004
+#define EAC_CPCFR3             0x0008
+#define EAC_CPCFR4             0x000C
+#define EAC_CPTCTL             0x0010
+#define EAC_CPTTADR            0x0014
+#define EAC_CPTDATL            0x0018
+#define EAC_CPTDATH            0x001C
+#define EAC_CPTVSLL            0x0020
+#define EAC_CPTVSLH            0x0024
+#define EAC_MPCTR              0x0040
+#define EAC_MPMCCFR            0x0044
+#define EAC_BPCTR              0x0060
+#define EAC_BPMCCFR            0x0064
+#define EAC_AMSCFR             0x0080
+#define EAC_AMVCTR             0x0084
+#define EAC_AM1VCTR            0x0088
+#define EAC_AM2VCTR            0x008C
+#define EAC_AM3VCTR            0x0090
+#define EAC_ASTCTR             0x0094
+#define EAC_APD1LCR            0x0098
+#define EAC_APD1RCR            0x009C
+#define EAC_APD2LCR            0x00A0
+#define EAC_APD2RCR            0x00A4
+#define EAC_APD3LCR            0x00A8
+#define EAC_APD3RCR            0x00AC
+#define EAC_APD4R              0x00B0
+#define EAC_ADWR               0x00B4
+#define EAC_ADRDR              0x00B8
+#define EAC_AGCFR              0x00BC
+#define EAC_AGCTR              0x00C0
+#define EAC_AGCFR2             0x00C4
+#define EAC_AGCFR3             0x00C8
+#define EAC_MBPDMACTR          0x00CC
+#define EAC_MPDDMARR           0x00D0
+#define EAC_MPDDMAWR           0x00D4
+#define EAC_MPUDMARR           0x00D8
+#define EAC_MPUDMAWR           0x00E0
+#define EAC_BPDDMARR           0x00E4
+#define EAC_BPDDMAWR           0x00E8
+#define EAC_BPUDMARR           0x00EC
+#define EAC_BPUDMAWR           0x00F0
+#define EAC_VERSION            0x0100
+#define EAC_SYSCONFIG          0x0104
+#define EAC_SYSSTATUS          0x0108
+
+/* CPTCTL */
+#define CPTCTL_RXF             (1 << 7)        /* receive data register full */
+#define CPTCTL_RXIE            (1 << 6)        /* receive interrupt enable */
+#define CPTCTL_TXE             (1 << 5)        /* transmit register empty */
+#define CPTCTL_TXIE            (1 << 4)        /* transmit interrupt enable */
+#define CPTCTL_CPEN            (1 << 3)        /* codec port enable */
+#define CPTCTL_CRST            (1 << 0)        /* external codec reset */
+
+/* CPCFR1 */
+#define CPCFR1_MTSL(val)       ((val & 0x1f) << 3)     /* number of time slots per frame */
+#define CPCFR1_MTSL_BITS       (0x1f << 3)
+#define CPCFR1_MODE(val)       ((val & 0x7) << 0)      /* codec port interface mode */
+#define CPCFR1_MODE_BITS       (0x7 << 0)
+
+/* CPCFR2 */
+#define CPCFR2_TSLOL(val)      ((val & 0x3) << 6)      /* time slot 0 length in number of serial clock (CLK_BIT) cycles */
+#define CPCFR2_TSLOL_BITS      (0x3 << 6)
+#define CPCFR2_BPTSL(val)      ((val & 0x7) << 3)      /* number of data bits per audio time slot */
+#define CPCFR2_BPTSL_BITS      (0x7 << 3)
+#define CPCFR2_TSLL(val)       ((val & 0x7) << 0)      /* time slot lenght (except slot 0) in number of serial clock cycles */
+#define CPCFR2_TSLL_BITS       (0x7 << 0)
+
+/* CPCFR3 */
+#define CPCFR3_DDLY            (1 << 7)        /* data delay: data bits start according to SYNC signal leading edge */
+#define CPCFR3_TRSEN           (1 << 6)        /* 3-state enable: data serial output state during nonvalid audio frames */
+#define CPCFR3_CLKBP           (1 << 5)        /* clock polarity */
+#define CPCFR3_CSYNCP          (1 << 4)        /* cp_sync(synchro) polarity */
+#define CPCFR3_CSYNCL          (1 << 3)        /* csync length */
+/* bit 2 reserved */
+#define CPCFR3_CSCLKD          (1 << 1)        /* cp_sclk port (serial clock) direction */
+#define CPCFR3_CSYNCD          (1 << 0)        /* cp_sync (synchro) direction */
+
+/* CPCFR4 */
+#define CPCFR4_ATSL(val)       ((val & 0xf) << 4)      /* audio time slots for secondary communication address and data values */
+#define CPCFR4_ATSL_BITS       (0xf << 4)
+#define CPCFR4_CLKS            (1 << 3)                /* clock source */
+#define CPCFR4_DIVB(val)       ((val & 0x7) << 0)      /* cp_sclk driver value */
+#define CPCFR4_DIVB_BITS       (0x7 << 0)
+
+/* AGCFR */
+#define AGCFR_MN_ST            (1 << 10)       /* mono/stereo audio file */
+#define AGCFR_B8_16            (1 << 9)        /* 8 bits/16 bits audio file */
+#define AGCFR_LI_BI            (1 << 8)        /* audio file endianism */
+#define AGCFR_FSINT(val)       ((val & 0x3) << 6) /* intermediate sample frequency for DMA read and write operations */
+#define AGCFR_FINST_BITS       (0x3 << 6)
+
+#define AGCFR_FSINT_8000       (0)             /* 8000  Hz */
+#define AGCFR_FSINT_11025      (1)             /* 11025 Hz */
+#define AGCFR_FSINT_22050      (2)             /* 22050 Hz */
+#define AGCFR_FSINT_44100      (3)             /* 44100 Hz */
+
+#define AGCFR_AUD_CKSRC(val)((val & 0x3) << 4) /* audio processing clock source */
+#define AGCFR_AUD_CKSRC_BITS   (0x3 << 4)
+#define AGCFR_M_CKSRC          (1 << 3)        /* modem interface clock source */
+#define AGCFR_MCLK_OUT         (1 << 1)
+#define AGCFR_MCLK             (1 << 0)
+
+
+/* AGCTR */
+#define AGCTR_AUDRD            (1 << 15)       /* audio ready */
+#define AGCTR_AUDRDI           (1 << 14)       /* audio ready interrupt status */
+#define AGCTR_AUDRDIEN         (1 << 13)       /* audio ready interrupt enable */
+#define AGCTR_DMAREN           (1 << 12)       /* audio files play operation */
+#define AGCTR_DMAWEN           (1 << 11)       /* audio file record operation */
+/* bits 10:4 reserved */
+#define AGCTR_MCLK_EN          (1 << 3)        /* internal MCLK enable */
+#define AGCTR_OSCMCLK_EN       (1 << 2)        /* OSCMCLK_EN output for MCLK oscillator control */
+#define AGCTR_AUDEN            (1 << 1)        /* audio processing enable/disable */
+#define AGCTR_EACPWD           (1 << 0)        /* EAC operation */
+
+/* AGCFR2 */
+#define AGCFR2_BT_MD_WIDEBAND  (1 << 5)        /* the BT device and modem AuSPIs wide-band mode */
+#define AGCFR2_MCLK_I2S_N11M_12M (1 << 4)      /* MCLK freq indicator for audio operations */
+#define AGCFR2_I2S_N44K_48K    (1 << 3)        /* Frame sample frecuency of I2S codec port, does not generate value */
+#define AGCFR2_FSINT2(val)     ((val & 0x7) << 0) /* intermediate sample frequency for DMA channel read and write operations */
+#define AGCFR2_FSINT2_BITS     (0x7 << 0)
+
+#define AGCFR2_FSINT2_8000     (0)             /* 8000  Hz */
+#define AGCFR2_FSINT2_11025    (1)             /* 11025 Hz */
+#define AGCFR2_FSINT2_22050    (2)             /* 22050 Hz */
+#define AGCFR2_FSINT2_44100    (3)             /* 44100 Hz */
+#define AGCFR2_FSINT2_48000    (4)             /* 48000 Hz */
+#define AGCFR2_FSINT2_FSINT    (7)             /* based on AGCFR/FSINT */
+
+
+/* AGCFR3 */
+#define AGCFR3_CP_TR_DMA       (1 << 15)       /* codec port transparent DMA (to audio DMAs) */
+#define AGCFR3_BT_TR_DMA       (1 << 14)       /* BT transparent DMA (to BT UL write & DL read DMAs */     
+#define AGCFR3_MD_TR_DMA       (1 << 13)       /* modem transparent DMA (to modem UL write and DL read DMAs) */
+#define AGCFR3_FSINT(val)      ((val & 0xf) << 9) /* FSINT */
+#define AGCFR3_FSINT_BITS      (0xf << 9)
+
+#define AGCFR3_FSINT_8000      (0)             /* 8000  Hz */
+#define AGCFR3_FSINT_11025     (1)             /* 11025 Hz */
+#define AGCFR3_FSINT_16000     (2)             /* 16000 Hz */
+#define AGCFR3_FSINT_22050     (3)             /* 22050 Hz */
+#define AGCFR3_FSINT_24000     (4)             /* 24000 Hz */
+#define AGCFR3_FSINT_32000     (5)             /* 32000 Hz */
+#define AGCFR3_FSINT_44100     (6)             /* 44100 Hz */
+#define AGCFR3_FSINT_48000     (7)             /* 48000 Hz */
+#define AGCFR3_FSINT_FSINT     (15)            /* based on AGCFR2/AGCFR */
+
+
+#define AGCFR3_BT_CKSRC(val)   ((val & 0x3) << 7)      /* BT port clock selection */
+#define AGCFR3_BT_CKSRC_BITS   (0x3 << 7)
+#define AGCFR3_MD_CKSRC(val)   ((val & 0x3) << 5)      /* modem port clock source */
+#define AGCFR3_MD_CKSRC_BITS   (0x3 << 5)
+#define AGCFR3_AUD_CKSRC(val)  ((val & 0x7) << 2)      /* audio and codec port clock source */
+#define AGCFR3_AUD_CKSRC_BITS  (0x7 << 2)
+#define AGCFR3_CLK12MINT_SEL   (1 << 1)                /* internal 12MHz clock source */
+#define AGCFR3_MCLKINT_SEL     (1 << 0)                /* internal codec master clock source */
+
+/* AMSCFR */
+#define AMSCFR_K12             (1 << 11)               /* K12 switch open/close */
+#define AMSCFR_K11             (1 << 10)
+#define AMSCFR_K10             (1 << 9)
+#define AMSCFR_K9              (1 << 8)
+#define AMSCFR_K8              (1 << 7)
+#define AMSCFR_K7              (1 << 6)
+#define AMSCFR_K6              (1 << 5)
+#define AMSCFR_K5              (1 << 4)
+#define AMSCFR_K4              (1 << 3)
+#define AMSCFR_K3              (1 << 2)
+#define AMSCFR_K2              (1 << 1)
+#define AMSCFR_K1              (1 << 0)
+
+/* AMVCTR */
+#define AMVCTR_GWO_BITS                (0xff << 8)
+#define AMVCTR_GWO(val)                ((val & 0xff) << 8)     /* Gain on write DMA operation */
+#define AMVCTR_GRO_BITS                (0xff << 0)
+#define AMVCTR_GRO(val)                ((val & 0xff) << 0)     /* Gain on read DMA operation */
+
+/* AM1VCTR */
+#define AM1VCTR_MUTE           (1 << 15)               /* mute/no mute on mixer output */
+#define AM1VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM1VCTR_GINB_BITS      (0x7f << 8)
+#define AM1VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM1VCTR_GINA_BITS      (0x7f << 0)
+
+/* AM2VCTR */
+#define AM2VCTR_MUTE           (1 << 15)               /* mute/no mute on mixer output */
+#define AM2VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM2VCTR_GINB_BITS      (0x7f << 8)
+#define AM2VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM2VCTR_GINA_BITS      (0x7f << 0)
+
+/* AM3VCTR */
+#define AM3VCTR_MUTE           (1 << 15)               /* mute/no mute */
+#define AM3VCTR_GINB(val)      ((val & 0x7f) << 8)     /* gain on input B */
+#define AM3VCTR_GINB_BITS      (0x7f << 8)
+#define AM3VCTR_GINA(val)      ((val & 0x7f) << 0)     /* gain on input A */
+#define AM3VCTR_GINA_BITS      (0x7f << 0)
+
+/* ASTCTR */
+#define ASTCTR_ATT(val)                ((val & 0x7f) << 1)     /* Attenuation of side tone */
+#define ASTCTR_ATT_BITS                (0x7f << 1)
+#define ASTCTR_ATTEN           (1 << 0)                /* side tone enabled/disabled */
+
+
+/* internal structure of the EAC driver */
+struct omap_eac {
+       struct mutex                    mutex;
+       void __iomem *                  base;
+       struct platform_device *        pdev;
+       struct eac_platform_data *      pdata;
+       struct snd_card *               card;
+       struct clk *                    fck;
+       struct clk *                    ick;
+       struct eac_codec *              codec;
+
+       unsigned                        clocks_enabled:1;
+};
+
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for OMAP24xx EAC");
+
+
+#define MOD_REG_BIT(val, mask, set) do { \
+       if (set) \
+               val |= mask; \
+       else \
+               val &= ~mask; \
+} while(0)
+
+static inline void eac_write_reg(struct omap_eac *eac, int idx, u16 val)
+{
+       __raw_writew(val, eac->base + idx);
+}
+
+static inline u16 eac_read_reg(struct omap_eac *eac, int idx)
+{
+       return __raw_readw(eac->base + idx);
+}
+
+static int eac_get_clocks(struct omap_eac *eac)
+{
+       eac->ick = clk_get(NULL, "eac_ick");
+       if (IS_ERR(eac->ick)) {
+               dev_err(&eac->pdev->dev, "Could not get eac_ick");
+               return -ENODEV;
+       }
+
+       eac->fck = clk_get(NULL, "eac_fck");
+       if (IS_ERR(eac->fck)) {
+               dev_err(&eac->pdev->dev, "Could not get eac_fck");
+               clk_put(eac->ick);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void eac_put_clocks(struct omap_eac *eac)
+{
+       clk_put(eac->fck);
+       clk_put(eac->ick);
+}
+
+static int eac_enable_clocks(struct omap_eac *eac)
+{
+       int err = 0;
+
+       if (eac->clocks_enabled)
+               return 0;
+
+       if (eac->pdata != NULL && eac->pdata->enable_ext_clocks != NULL) {
+               if ((err = eac->pdata->enable_ext_clocks(&eac->pdev->dev)) != 0)
+                       return err;
+       }
+       clk_enable(eac->ick);
+       clk_enable(eac->fck);
+       eac->clocks_enabled = 1;
+
+       return 0;
+}
+
+static void eac_disable_clocks(struct omap_eac *eac)
+{
+       if (!eac->clocks_enabled)
+               return;
+       eac->clocks_enabled = 0;
+
+       clk_disable(eac->fck);
+       clk_disable(eac->ick);
+       if (eac->pdata != NULL && eac->pdata->disable_ext_clocks != NULL)
+               eac->pdata->disable_ext_clocks(&eac->pdev->dev);
+}
+
+static int eac_reset(struct omap_eac *eac)
+{
+       int i;
+
+       /* step 1 (see TRM) */
+       /* first, let's reset the EAC */
+       eac_write_reg(eac, EAC_SYSCONFIG, 0x2);
+       /* step 2 (see TRM) */
+       eac_write_reg(eac, EAC_AGCTR, AGCTR_MCLK_EN | AGCTR_AUDEN);
+       /* step 3 (see TRM) */
+       /* wait until reset done */
+       i = 10000;
+       while (!(eac_read_reg(eac, EAC_SYSSTATUS) & 1)) {
+               if (--i == 0)
+                       return -ENODEV;
+               udelay(1);
+       }
+
+       return 0;
+}
+
+static int eac_calc_agcfr3_fsint(int rate)
+{
+       int fsint;
+
+       if (rate >= 48000)
+               fsint = AGCFR3_FSINT_48000;
+       else if (rate >= 44100)
+               fsint = AGCFR3_FSINT_44100;
+       else if (rate >= 32000)
+               fsint = AGCFR3_FSINT_32000;
+       else if (rate >= 24000)
+               fsint = AGCFR3_FSINT_24000;
+       else if (rate >= 22050)
+               fsint = AGCFR3_FSINT_22050;
+       else if (rate >= 16000)
+               fsint = AGCFR3_FSINT_16000;
+       else if (rate >= 11025)
+               fsint = AGCFR3_FSINT_11025;
+       else
+               fsint = AGCFR3_FSINT_8000;
+
+       return fsint;
+}
+
+static int eac_configure_pcm(struct omap_eac *eac, struct eac_codec *conf)
+{
+       dev_err(&eac->pdev->dev,
+               "EAC codec port configuration for PCM not implemented\n");
+
+       return -ENODEV;
+}
+
+static int eac_configure_ac97(struct omap_eac *eac, struct eac_codec *conf)
+{
+       dev_err(&eac->pdev->dev,
+               "EAC codec port configuration for AC97 not implemented\n");
+
+       return -ENODEV;
+}
+
+static int eac_configure_i2s(struct omap_eac *eac, struct eac_codec *conf)
+{
+       u16 cpcfr1, cpcfr2, cpcfr3, cpcfr4;
+
+       cpcfr1 = eac_read_reg(eac, EAC_CPCFR1);
+       cpcfr2 = eac_read_reg(eac, EAC_CPCFR2);
+       cpcfr3 = eac_read_reg(eac, EAC_CPCFR3);
+       cpcfr4 = eac_read_reg(eac, EAC_CPCFR4);
+
+       cpcfr1 &= ~(CPCFR1_MODE_BITS | CPCFR1_MTSL_BITS);
+       cpcfr1 |= CPCFR1_MTSL(1); /* 2 timeslots per frame (I2S default) */
+
+       /* audio time slot configuration for I2S mode */
+       cpcfr2 &= ~(CPCFR2_TSLL_BITS | CPCFR2_BPTSL_BITS | CPCFR2_TSLOL_BITS);
+       cpcfr2 |= CPCFR2_TSLOL(0); /* time slot 0 length same as TSLL */
+       cpcfr2 |= CPCFR2_BPTSL(1); /* 16 data bits per time slot */
+       cpcfr2 |= CPCFR2_TSLL(1); /* time slot length 16 serial clock cycles */
+
+       /* I2S link configuration */
+       MOD_REG_BIT(cpcfr3, CPCFR3_DDLY,
+               conf->codec_conf.i2s.sync_delay_enable); /* 0/1 clk delay */
+       /* data serial output enabled during nonvalid audio frames, clock
+        * polarity = falling edge, CSYNC lenght equal to time slot0 length */
+       MOD_REG_BIT(cpcfr3, CPCFR3_TRSEN, 1);
+       MOD_REG_BIT(cpcfr3, CPCFR3_CLKBP, 1);
+       MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCL, 1);
+
+       cpcfr4 &= ~(CPCFR4_DIVB_BITS | CPCFR4_ATSL_BITS);
+       cpcfr4 |= CPCFR4_DIVB(7); /* CP_SCLK = MCLK / 8 */
+
+       /* configuration for normal I2S or polarity-changed I2S */
+       if (!conf->codec_conf.i2s.polarity_changed_mode) {
+               cpcfr1 |= CPCFR1_MODE(4); /* I2S mode */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 0); /* CP_SYNC active low */
+               /* audio time slots configuration for I2S */
+               cpcfr4 |= CPCFR4_ATSL(0);
+       } else {
+               cpcfr1 |= CPCFR1_MODE(1); /* PCM mode/polarity-changed I2S */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCP, 1); /* CP_SYNC active
+                                                         high */
+               /* audio time slots configuration for polarity-changed I2S */
+               cpcfr4 |= CPCFR4_ATSL(0xf);
+       };
+
+       /* master/slave configuration */
+       if (conf->codec_mode == EAC_CODEC_I2S_MASTER) {
+               /* EAC is master. Set CP_SCLK and CP_SYNC as outputs */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 0);
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 0);
+       } else {
+               /* EAC is slave. Set CP_SCLK and CP_SYNC as inputs */
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSCLKD, 1);
+               MOD_REG_BIT(cpcfr3, CPCFR3_CSYNCD, 1);
+       }
+
+       eac_write_reg(eac, EAC_CPCFR1, cpcfr1);
+       eac_write_reg(eac, EAC_CPCFR2, cpcfr2);
+       eac_write_reg(eac, EAC_CPCFR3, cpcfr3);
+       eac_write_reg(eac, EAC_CPCFR4, cpcfr4);
+
+       return 0;
+}
+
+static int eac_codec_port_init(struct omap_eac *eac, struct eac_codec *conf)
+{
+       u16 agcfr, agcfr2, agcfr3, agctr;
+       u16 cpctl, reg;
+       int err = 0, i;
+
+       /* use internal MCLK gating before doing full configuration for it.
+        * Partial or misconfigured MCLK will cause that access to some of the
+        * EAC registers causes "external abort on linefetch". Same happens
+        * also when using external clock as a MCLK source and if that clock is
+        * either missing or not having a right rate (e.g. half of it) */
+       agcfr3 = eac_read_reg(eac, EAC_AGCFR3);
+       MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 1); /* 96 Mhz / 8.5 */
+       eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+
+       /* disable codec port, enable access to config registers */
+       cpctl = eac_read_reg(eac, EAC_CPTCTL);
+       MOD_REG_BIT(cpctl, CPTCTL_CPEN, 0);
+       eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+       agcfr = eac_read_reg(eac, EAC_AGCFR);
+       agctr = eac_read_reg(eac, EAC_AGCTR);
+       agcfr2 = eac_read_reg(eac, EAC_AGCFR2);
+
+       /* MCLK source and frequency configuration */
+       MOD_REG_BIT(agcfr, AGCFR_MCLK, 0);
+       switch (conf->mclk_src) {
+       case EAC_MCLK_EXT_2x11289600:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+               MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+       case EAC_MCLK_EXT_11289600:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1);
+               MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 0); /* 44.1 kHz */
+               MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 0); /* 11.2896 */
+               MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+               break;
+
+       case EAC_MCLK_EXT_2x12288000:
+               MOD_REG_BIT(agcfr, AGCFR_MCLK, 1); /* div by 2 path */
+               MOD_REG_BIT(agcfr, AGCFR_MCLK_OUT, 1); /* div by 2 */
+       case EAC_MCLK_EXT_12288000:
+               MOD_REG_BIT(agcfr2, AGCFR2_I2S_N44K_48K, 1); /* 48 kHz */
+               MOD_REG_BIT(agcfr2, AGCFR2_MCLK_I2S_N11M_12M, 1); /* 12.288 */
+               MOD_REG_BIT(agcfr3, AGCFR3_MCLKINT_SEL, 0);
+               break;
+
+       default:
+               /* internal MCLK gating */
+               break;
+       }
+       MOD_REG_BIT(agctr, AGCTR_MCLK_EN, 1);
+       MOD_REG_BIT(agctr, AGCTR_OSCMCLK_EN, 1); /* oscillator enabled? */
+       /* use MCLK just configured above as audio & codec port clock source */
+       agcfr3 &= ~AGCFR3_AUD_CKSRC_BITS;
+       agcfr3 |= AGCFR3_AUD_CKSRC(0);
+
+       /* audio data format */
+       MOD_REG_BIT(agcfr, AGCFR_MN_ST, 1);     /* stereo file */
+       MOD_REG_BIT(agcfr, AGCFR_B8_16, 1);     /* 16 bit audio file */
+       MOD_REG_BIT(agcfr, AGCFR_LI_BI, 0);     /* little endian stream */
+
+       /* there are FSINT configuration bits in AGCFR, AGCFR2 and AGCFR3
+        * registers but it seems that it is just enough to set in AGCFR3
+        * only */
+       agcfr3 &= ~AGCFR3_FSINT_BITS;
+       agcfr3 |= AGCFR3_FSINT(eac_calc_agcfr3_fsint(conf->default_rate));
+
+       /* transparent DMA enable bits */
+       MOD_REG_BIT(agcfr3, AGCFR3_MD_TR_DMA, 1); /* modem */
+       MOD_REG_BIT(agcfr3, AGCFR3_BT_TR_DMA, 1); /* BT */
+       if (conf->codec_mode != EAC_CODEC_I2S_SLAVE)
+               MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 0);
+       else
+               MOD_REG_BIT(agcfr3, AGCFR3_CP_TR_DMA, 1);
+
+       /* step 4 (see TRM) */
+       eac_write_reg(eac, EAC_AGCFR3, agcfr3);
+       /* pre-write AGCTR now (finally in step 10) in order to get MCLK
+        * settings effective (especially when using external MCLK) */
+       eac_write_reg(eac, EAC_AGCTR, agctr);
+       eac_write_reg(eac, EAC_AGCFR2, agcfr2);
+
+       /* step 5 (see TRM) */
+       eac_write_reg(eac, EAC_AGCFR, agcfr);
+
+       /* step 6 (see TRM) */
+       /* wait until audio reset done */
+       i = 10000;
+       while (!(eac_read_reg(eac, EAC_SYSSTATUS) & (1 << 3))) {
+               if (--i == 0)
+                       return -ETIMEDOUT;
+               udelay(1);
+       }
+
+       /* step 7 (see TRM) */
+       reg = eac_read_reg(eac, EAC_AMSCFR);
+       MOD_REG_BIT(reg, AMSCFR_K1, 1);         /* K1 switch closed */
+       MOD_REG_BIT(reg, AMSCFR_K5, 1);         /* K5 switch closed */
+       MOD_REG_BIT(reg, AMSCFR_K2, 0);         /* K2 switch open */
+       MOD_REG_BIT(reg, AMSCFR_K6, 0);         /* K6 switch open */
+       eac_write_reg(eac, EAC_AMSCFR, reg);
+
+       /* step 8 (see TRM) */
+       switch (conf->codec_mode) {
+       case EAC_CODEC_PCM:
+               err = eac_configure_pcm(eac, conf);
+               break;
+       case EAC_CODEC_AC97:
+               err = eac_configure_ac97(eac, conf);
+               break;
+       default:
+               err = eac_configure_i2s(eac, conf);
+               break;
+       }
+
+       /* step 9 (see TRM) */
+       MOD_REG_BIT(cpctl, CPTCTL_CPEN, 1);     /* codec port enable */
+       MOD_REG_BIT(cpctl, CPTCTL_RXIE, 1);     /* receive int enable */
+       MOD_REG_BIT(cpctl, CPTCTL_TXIE, 1);     /* transmit int enable */
+       eac_write_reg(eac, EAC_CPTCTL, cpctl);
+
+       /* step 10 (see TRM) */
+       /* enable playing & recording */
+       MOD_REG_BIT(agctr, AGCTR_DMAREN, 1);    /* playing enabled (DMA R) */
+       MOD_REG_BIT(agctr, AGCTR_DMAWEN, 1);    /* recording enabled (DMA W) */
+       MOD_REG_BIT(agctr, AGCTR_AUDEN, 1);     /* audio processing enabled */
+       eac_write_reg(eac, EAC_AGCTR, agctr);
+
+       /* audio mixer1, no mute on mixer output, gain = 0 dB */
+       reg = eac_read_reg(eac, EAC_AM1VCTR);
+       MOD_REG_BIT(reg, AM1VCTR_MUTE, 0);
+       reg = ((reg & ~AM1VCTR_GINB_BITS) | (AM1VCTR_GINB(0x67)));
+       eac_write_reg(eac, EAC_AM1VCTR, reg);
+
+       /* audio mixer3, no mute on mixer output, gain = 0 dB */
+       reg = eac_read_reg(eac, EAC_AM3VCTR);
+       MOD_REG_BIT(reg, AM3VCTR_MUTE, 0);
+       reg = ((reg & ~AM3VCTR_GINB_BITS) | (AM3VCTR_GINB(0x67)));
+       eac_write_reg(eac, EAC_AM3VCTR, reg);
+
+       /* audio side tone disabled */
+       eac_write_reg(eac, EAC_ASTCTR, 0x0);
+
+       return 0;
+}
+
+int eac_set_mode(struct device *dev, int play, int rec)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "EAC mode: play %s, rec %s\n",
+              play ? "enabled" : "disabled",
+              rec  ? "enabled" : "disabled");
+#endif
+       BUG_ON(eac == NULL);
+       mutex_lock(&eac->mutex);
+       if (play || rec) {
+               /* activate clocks */
+               eac_enable_clocks(eac);
+
+               /* power-up codec */
+               if (eac->codec != NULL && eac->codec->set_power != NULL)
+                       eac->codec->set_power(eac->codec->private_data,
+                               play, rec);
+       } else {
+               /* shutdown codec */
+               if (eac->codec != NULL && eac->codec->set_power != NULL)
+                       eac->codec->set_power(eac->codec->private_data, 0, 0);
+
+               /* de-activate clocks */
+               eac_disable_clocks(eac);
+       }
+       mutex_unlock(&eac->mutex);
+
+       return 0;
+}
+
+int eac_register_codec(struct device *dev, struct eac_codec *codec)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+       struct snd_card *card = eac->card;
+       int err;
+
+       BUG_ON(eac->codec != NULL);
+
+       mutex_lock(&eac->mutex);
+       eac->codec = codec;
+       eac_enable_clocks(eac);
+       err = eac_codec_port_init(eac, codec);
+       eac_disable_clocks(eac);
+       mutex_unlock(&eac->mutex);
+       if (err)
+               return err;
+
+       /* register mixer controls implemented by a codec driver */
+       if (codec->register_controls != NULL) {
+               err = codec->register_controls(codec->private_data, card);
+               if (err)
+                       return err;
+       }
+
+       if (codec->short_name != NULL) {
+               sprintf(card->longname, "%s with codec %s", card->shortname,
+                       codec->short_name);
+               strcpy(card->mixername, codec->short_name);
+       }
+
+       err = snd_card_register(card);
+       return err;
+}
+
+void eac_unregister_codec(struct device *dev)
+{
+       struct omap_eac *eac = dev_get_drvdata(dev);
+
+       BUG_ON(eac->codec == NULL);
+       eac_set_mode(dev, 0, 0);
+       snd_card_disconnect(eac->card);
+       eac->codec = NULL;
+}
+
+static int __devinit eac_probe(struct platform_device *pdev)
+{
+       struct eac_platform_data *pdata = pdev->dev.platform_data;
+       struct snd_card *card;
+       struct omap_eac *eac;
+       struct resource *res;
+       int err;
+
+       eac = kzalloc(sizeof(*eac), GFP_KERNEL);
+       if (!eac)
+               return -ENOMEM;
+
+       mutex_init(&eac->mutex);
+       eac->pdev = pdev;
+       platform_set_drvdata(pdev, eac);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               err = -ENODEV;
+               goto err1;
+       }
+       eac->base = ioremap(res->start, res->end - res->start + 1);
+       eac->pdata = pdata;
+
+       /* pre-initialize EAC hw */
+       err = eac_get_clocks(eac);
+       if (err)
+               goto err1;
+       err = eac_enable_clocks(eac);
+       if (err)
+               goto err2;
+
+       err = eac_reset(eac);
+       if (err)
+               goto err3;
+
+       dev_info(&pdev->dev, "EAC version: %d.%d\n",
+                eac_read_reg(eac, EAC_VERSION) >> 4,
+                eac_read_reg(eac, EAC_VERSION) & 0x0f);
+       eac_disable_clocks(eac);
+
+       /* create soundcard instance */
+       card = snd_card_new(-1, id, THIS_MODULE, 0);
+       if (card == NULL) {
+               err = -ENOMEM;
+               goto err3;
+       }
+       eac->card = card;
+       strcpy(card->driver, "EAC");
+       strcpy(card->shortname, "OMAP24xx EAC");
+
+       sprintf(card->longname, "%s", card->shortname);
+       strcpy(card->mixername, "EAC Mixer");
+
+       if (eac->pdata->init) {
+               err = eac->pdata->init(&pdev->dev);
+               if (err < 0) {
+                       printk("init %d\n", err);
+                       goto err4;
+               }
+       }
+
+       return 0;
+
+err4:
+       snd_card_free(card);
+err3:
+       eac_disable_clocks(eac);
+err2:
+       eac_put_clocks(eac);
+err1:
+       kfree(eac);
+       return err;
+}
+
+static int __devexit eac_remove(struct platform_device *pdev)
+{
+       struct omap_eac *eac = platform_get_drvdata(pdev);
+       struct snd_card *card = eac->card;
+
+       snd_card_free(card);
+
+       eac_disable_clocks(eac);
+       eac_put_clocks(eac);
+
+       iounmap(eac->base);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver eac_driver = {
+       .driver = {
+               .name           = "omap24xx-eac",
+               .bus            = &platform_bus_type,
+       },
+       .probe          = eac_probe,
+       .remove         = eac_remove,
+};
+
+static int __init eac_init(void)
+{
+       return platform_driver_register(&eac_driver);
+}
+
+static void __exit eac_exit(void)
+{
+       platform_driver_unregister(&eac_driver);
+}
+
+module_init(eac_init);
+module_exit(eac_exit);
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/omap/omap-alsa-aic23-mixer.c b/sound/arm/omap/omap-alsa-aic23-mixer.c
new file mode 100644 (file)
index 0000000..da2a875
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * sound/arm/omap/omap-alsa-aic23-mixer.c
+ *
+ * Alsa Driver Mixer for generic codecs for omap boards
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by David Cohen, Daniel Petrini
+ *            {david.cohen, daniel.petrini}@indt.org.br
+ *
+ * Based on es1688_lib.c,
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-08-02   INdT Kernel Team - Alsa mixer driver for omap osk.
+ *                             Creation of new file omap-alsa-mixer.c.
+ *                             Initial version with aic23 codec for osk5912
+ */
+
+#include <linux/kernel.h>
+
+#include <mach/aic23.h>
+
+#include <mach/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+#include <sound/initval.h>
+#include <sound/control.h>
+
+MODULE_AUTHOR("David Cohen");
+MODULE_AUTHOR("Daniel Petrini");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP Alsa mixer driver for ALSA");
+
+/*
+ * Codec dependent region
+ */
+
+/* Codec AIC23 */
+#if defined(CONFIG_SENSORS_TLV320AIC23) || \
+       defined(CONFIG_SENSORS_TLV320AIC23_MODULE)
+
+#define MIXER_NAME                  "Mixer AIC23"
+#define SND_OMAP_WRITE(reg, val)     audio_aic23_write(reg, val)
+
+#endif
+
+/* Callback Functions */
+#define OMAP_BOOL(xname, xindex, reg, reg_index, mask, invert) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_bool, \
+       .get = snd_omap_get_bool, \
+       .put = snd_omap_put_bool, \
+       .private_value = reg | (reg_index << 8) | (invert << 10) | \
+                               (mask << 12) \
+}
+
+#define OMAP_MUX(xname, reg, reg_index, mask) \
+{ \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .info = snd_omap_info_mux, \
+       .get = snd_omap_get_mux, \
+       .put = snd_omap_put_mux, \
+       .private_value = reg | (reg_index << 8) | (mask << 10) \
+}
+
+#define OMAP_SINGLE(xname, xindex, reg, reg_index, reg_val, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_single, \
+       .get = snd_omap_get_single, \
+       .put = snd_omap_put_single, \
+       .private_value = reg | (reg_val << 8) | (reg_index << 16) |\
+                               (mask << 18) \
+}
+
+#define OMAP_DOUBLE(xname, xindex, left_reg, right_reg, reg_index, mask) \
+{\
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .index = xindex, \
+       .info = snd_omap_info_double, \
+       .get = snd_omap_get_double, \
+       .put = snd_omap_put_double, \
+       .private_value = left_reg | (right_reg << 8) | (reg_index << 16) | \
+                               (mask << 18) \
+}
+
+/* Local Registers */
+enum snd_device_index {
+       PCM_INDEX = 0,
+       LINE_INDEX,
+       AAC_INDEX, /* Analog Audio Control: reg = l_reg */
+};
+
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_regs[3];
+
+#ifdef CONFIG_PM
+struct {
+       u16 l_reg;
+       u16 r_reg;
+       u8 sw;
+} omap_pm_regs[3];
+#endif
+
+u16 snd_sidetone[6] = {
+       SIDETONE_18,
+       SIDETONE_12,
+       SIDETONE_9,
+       SIDETONE_6,
+       SIDETONE_0,
+       0
+};
+
+/* Begin Bool Functions */
+
+static int snd_omap_info_bool(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+static int snd_omap_get_bool(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       if (invert)
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 0 : 1;
+       else
+               ucontrol->value.integer.value[0] =
+                       (omap_regs[mic_index].l_reg & mask) ? 1 : 0;
+
+       return 0;
+}
+
+static int snd_omap_put_bool(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       int mic_index = (kcontrol->private_value >> 8) & 0x03;
+       u16 mask = (kcontrol->private_value >> 12) & 0xff;
+       u16 reg = kcontrol->private_value & 0xff;
+       int invert = (kcontrol->private_value >> 10) & 0x03;
+
+       int changed = 1;
+
+       if (ucontrol->value.integer.value[0]) /* XOR */
+               if (invert)
+                       omap_regs[mic_index].l_reg &= ~mask;
+               else
+                       omap_regs[mic_index].l_reg |= mask;
+       else
+               if (invert)
+                       omap_regs[mic_index].l_reg |= mask;
+               else
+                       omap_regs[mic_index].l_reg &= ~mask;
+
+       SND_OMAP_WRITE(reg, omap_regs[mic_index].l_reg);
+
+       return changed;
+}
+
+/* End Bool Functions */
+
+/* Begin Mux Functions */
+
+static int snd_omap_info_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       /* Mic = 0
+        * Line = 1 */
+       static char *texts[2] = { "Mic", "Line" };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = 2;
+
+       if (uinfo->value.enumerated.item > 1)
+               uinfo->value.enumerated.item = 1;
+
+       strcpy(uinfo->value.enumerated.name,
+                       texts[uinfo->value.enumerated.item]);
+
+       return 0;
+}
+
+static int snd_omap_get_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_idx = (kcontrol->private_value >> 8) & 0x03;
+
+       ucontrol->value.enumerated.item[0] =
+               (omap_regs[mux_idx].l_reg & mask) ? 0 /* Mic */ : 1 /* Line */;
+
+       return 0;
+}
+
+static int snd_omap_put_mux(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 mask = (kcontrol->private_value >> 10) & 0xff;
+       int mux_index = (kcontrol->private_value >> 8) & 0x03;
+
+       int changed = 1;
+
+       if (!ucontrol->value.integer.value[0])
+               omap_regs[mux_index].l_reg |= mask; /* AIC23: Mic */
+       else
+               omap_regs[mux_index].l_reg &= ~mask; /* AIC23: Line */
+
+       SND_OMAP_WRITE(reg, omap_regs[mux_index].l_reg);
+
+       return changed;
+}
+
+/* End Mux Functions */
+
+/* Begin Single Functions */
+
+static int snd_omap_info_single(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = reg_val-1;
+
+       return 0;
+}
+
+static int snd_omap_get_single(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       ucontrol->value.integer.value[0] = snd_sidetone[reg_val];
+
+       return 0;
+}
+
+static int snd_omap_put_single(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 reg_index = (kcontrol->private_value >> 16) & 0x03;
+       u16 mask = (kcontrol->private_value >> 18) & 0x1ff;
+       u16 reg = kcontrol->private_value & 0xff;
+       u16 reg_val = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       /* Volume */
+       if ((omap_regs[reg_index].l_reg !=
+                (ucontrol->value.integer.value[0] & mask))) {
+               changed = 1;
+
+               omap_regs[reg_index].l_reg &= ~mask;
+               omap_regs[reg_index].l_reg |=
+                       snd_sidetone[ucontrol->value.integer.value[0]];
+
+               snd_sidetone[reg_val] = ucontrol->value.integer.value[0];
+               SND_OMAP_WRITE(reg, omap_regs[reg_index].l_reg);
+       } else {
+               changed = 0;
+       }
+
+       return changed;
+}
+
+/* End Single Functions */
+
+/* Begin Double Functions */
+
+static int snd_omap_info_double(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       /*
+        * mask == 0 : Switch
+        * mask != 0 : Volume
+        */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+
+       uinfo->type = mask ? SNDRV_CTL_ELEM_TYPE_INTEGER :
+                       SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = mask ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = mask ? mask : 1;
+
+       return 0;
+}
+
+static int snd_omap_get_double(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       /*
+        * mask == 0 : Switch
+        * mask != 0 : Volume
+        */
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+
+       if (!mask) {
+               /* Switch */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].sw;
+       } else {
+               /* Volume */
+               ucontrol->value.integer.value[0] = omap_regs[vol_index].l_reg;
+               ucontrol->value.integer.value[1] = omap_regs[vol_index].r_reg;
+       }
+
+       return 0;
+}
+
+static int snd_omap_put_double(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mask == 0 : Switch
+        * mask != 0 : Volume */
+       int vol_index = (kcontrol->private_value >> 16) & 0x03;
+       int mask = (kcontrol->private_value >> 18) & 0xff;
+       int left_reg = kcontrol->private_value & 0xff;
+       int right_reg = (kcontrol->private_value >> 8) & 0xff;
+
+       int changed = 0;
+
+       if (!mask) {
+               /* Switch */
+               if (!ucontrol->value.integer.value[0]) {
+                       SND_OMAP_WRITE(left_reg, 0x00);
+                       SND_OMAP_WRITE(right_reg, 0x00);
+               } else {
+                       SND_OMAP_WRITE(left_reg, omap_regs[vol_index].l_reg);
+                       SND_OMAP_WRITE(right_reg, omap_regs[vol_index].r_reg);
+               }
+               changed = 1;
+               omap_regs[vol_index].sw = ucontrol->value.integer.value[0];
+       } else {
+               /* Volume */
+               if ((omap_regs[vol_index].l_reg !=
+                               (ucontrol->value.integer.value[0] & mask)) ||
+                       (omap_regs[vol_index].r_reg !=
+                               (ucontrol->value.integer.value[1] & mask))) {
+                       changed = 1;
+
+                       omap_regs[vol_index].l_reg &= ~mask;
+                       omap_regs[vol_index].r_reg &= ~mask;
+                       omap_regs[vol_index].l_reg |=
+                               (ucontrol->value.integer.value[0] & mask);
+                       omap_regs[vol_index].r_reg |=
+                               (ucontrol->value.integer.value[1] & mask);
+                       if (omap_regs[vol_index].sw) {
+                               /* write to registers only if sw is actived */
+                               SND_OMAP_WRITE(left_reg,
+                                               omap_regs[vol_index].l_reg);
+                               SND_OMAP_WRITE(right_reg,
+                                               omap_regs[vol_index].r_reg);
+                       }
+               } else {
+                       changed = 0;
+               }
+       }
+
+       return changed;
+}
+
+/* End Double Functions */
+
+static struct snd_kcontrol_new snd_omap_controls[] = {
+       OMAP_DOUBLE("PCM Playback Switch", 0, LEFT_CHANNEL_VOLUME_ADDR,
+                       RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX, 0x00),
+       OMAP_DOUBLE("PCM Playback Volume", 0, LEFT_CHANNEL_VOLUME_ADDR,
+                       RIGHT_CHANNEL_VOLUME_ADDR, PCM_INDEX,
+                       OUTPUT_VOLUME_MASK),
+       OMAP_BOOL("Line Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+                       AAC_INDEX, BYPASS_ON, 0),
+       OMAP_DOUBLE("Line Capture Switch", 0, LEFT_LINE_VOLUME_ADDR,
+                       RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, 0x00),
+       OMAP_DOUBLE("Line Capture Volume", 0, LEFT_LINE_VOLUME_ADDR,
+                       RIGHT_LINE_VOLUME_ADDR, LINE_INDEX, INPUT_VOLUME_MASK),
+       OMAP_BOOL("Mic Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+                       AAC_INDEX, STE_ENABLED, 0),
+       OMAP_SINGLE("Mic Playback Volume", 0, ANALOG_AUDIO_CONTROL_ADDR,
+                       AAC_INDEX, 5, SIDETONE_MASK),
+       OMAP_BOOL("Mic Capture Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+                       AAC_INDEX, MICM_MUTED, 1),
+       OMAP_BOOL("Mic Booster Playback Switch", 0, ANALOG_AUDIO_CONTROL_ADDR,
+                       AAC_INDEX, MICB_20DB, 0),
+       OMAP_MUX("Capture Source", ANALOG_AUDIO_CONTROL_ADDR, AAC_INDEX,
+                       INSEL_MIC),
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+       /* Saves current values to wake-up correctly */
+       omap_pm_regs[LINE_INDEX].l_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].r_reg = omap_regs[LINE_INDEX].l_reg;
+       omap_pm_regs[LINE_INDEX].sw = omap_regs[LINE_INDEX].sw;
+
+       omap_pm_regs[AAC_INDEX].l_reg = omap_regs[AAC_INDEX].l_reg;
+
+       omap_pm_regs[PCM_INDEX].l_reg = omap_regs[PCM_INDEX].l_reg;
+       omap_pm_regs[PCM_INDEX].r_reg = omap_regs[PCM_INDEX].r_reg;
+       omap_pm_regs[PCM_INDEX].sw = omap_regs[PCM_INDEX].sw;
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* Line's saved values */
+       omap_regs[LINE_INDEX].l_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].r_reg = omap_pm_regs[LINE_INDEX].l_reg;
+       omap_regs[LINE_INDEX].sw = omap_pm_regs[LINE_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR, omap_pm_regs[LINE_INDEX].l_reg);
+
+       /* Analog Audio Control's saved values */
+       omap_regs[AAC_INDEX].l_reg = omap_pm_regs[AAC_INDEX].l_reg;
+       SND_OMAP_WRITE(ANALOG_AUDIO_CONTROL_ADDR, omap_regs[AAC_INDEX].l_reg);
+
+       /* Headphone's saved values */
+       omap_regs[PCM_INDEX].l_reg = omap_pm_regs[PCM_INDEX].l_reg;
+       omap_regs[PCM_INDEX].r_reg = omap_pm_regs[PCM_INDEX].r_reg;
+       omap_regs[PCM_INDEX].sw = omap_pm_regs[PCM_INDEX].sw;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR,
+                       omap_pm_regs[PCM_INDEX].l_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR,
+                       omap_pm_regs[PCM_INDEX].r_reg);
+}
+#endif
+
+void snd_omap_init_mixer(void)
+{
+       u16 vol_reg;
+
+       /* Line's default values */
+       omap_regs[LINE_INDEX].l_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].r_reg = DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK;
+       omap_regs[LINE_INDEX].sw = 0;
+       SND_OMAP_WRITE(LEFT_LINE_VOLUME_ADDR,
+                       DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+       SND_OMAP_WRITE(RIGHT_LINE_VOLUME_ADDR,
+                       DEFAULT_INPUT_VOLUME & INPUT_VOLUME_MASK);
+
+       /* Analog Audio Control's default values */
+       omap_regs[AAC_INDEX].l_reg = DEFAULT_ANALOG_AUDIO_CONTROL;
+
+       /* Headphone's default values */
+       vol_reg = LZC_ON;
+       vol_reg &= ~OUTPUT_VOLUME_MASK;
+       vol_reg |= DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].l_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].r_reg = DEFAULT_OUTPUT_VOLUME;
+       omap_regs[PCM_INDEX].sw = 1;
+       SND_OMAP_WRITE(LEFT_CHANNEL_VOLUME_ADDR, vol_reg);
+       SND_OMAP_WRITE(RIGHT_CHANNEL_VOLUME_ADDR, vol_reg);
+}
+
+int snd_omap_mixer(struct snd_card_omap_codec *chip)
+{
+       struct snd_card *card;
+       unsigned int idx;
+       int err;
+
+       snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
+
+       card = chip->card;
+
+       strcpy(card->mixername, MIXER_NAME);
+
+       /* Registering alsa mixer controls */
+       for (idx = 0; idx < ARRAY_SIZE(snd_omap_controls); idx++) {
+               err = snd_ctl_add(card,
+                       snd_ctl_new1(&snd_omap_controls[idx], chip));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
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..9820e51
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * arch/arm/mach-omap1/omap-alsa-aic23.c
+ *
+ * Alsa codec Driver for AIC23 chip on OSK5912 platform board
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based in former alsa driver for osk and oss driver
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <linux/clk.h>
+#include <mach/clock.h>
+#include <mach/aic23.h>
+
+#include <mach/omap-alsa.h>
+#include "omap-alsa-aic23.h"
+
+static struct clk *aic23_mclk;
+
+/* aic23 related */
+static const struct aic23_samplerate_reg_info
+ rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       {4000, 0x06, 1},                /*  4000 */
+       {8000, 0x06, 0},                /*  8000 */
+       {16000, 0x0C, 1},               /* 16000 */
+       {22050, 0x11, 1},               /* 22050 */
+       {24000, 0x00, 1},               /* 24000 */
+       {32000, 0x0C, 0},               /* 32000 */
+       {44100, 0x11, 0},               /* 44100 */
+       {48000, 0x00, 0},               /* 48000 */
+       {88200, 0x1F, 0},               /* 88200 */
+       {96000, 0x0E, 0},               /* 96000 */
+};
+
+/*
+ * Hardware capabilities
+ */
+
+ /*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       4000, 8000, 16000, 22050,
+       24000, 32000, 44100,
+       48000, 88200, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list aic23_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_pcm_hardware aic23_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware aic23_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/*
+ * Codec/mcbsp init and configuration section
+ * codec dependent code.
+ */
+
+/* TLV320AIC23 is a write only device */
+void audio_aic23_write(u8 address, u16 data)
+{
+       aic23_write_value(address, data);
+}
+EXPORT_SYMBOL_GPL(audio_aic23_write);
+
+/*
+ * Sample rate changing
+ */
+void aic23_set_samplerate(long rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+
+       /* Fix the rate if it has a wrong value */
+       if (rate >= 96000)
+               rate = 96000;
+       else if (rate >= 88200)
+               rate = 88200;
+       else if (rate >= 48000)
+               rate = 48000;
+       else if (rate >= 44100)
+               rate = 44100;
+       else if (rate >= 32000)
+               rate = 32000;
+       else if (rate >= 24000)
+               rate = 24000;
+       else if (rate >= 22050)
+               rate = 22050;
+       else if (rate >= 16000)
+               rate = 16000;
+       else if (rate >= 8000)
+               rate = 8000;
+       else
+               rate = 4000;
+
+       /* Search for the right sample rate */
+       /* Verify what happens if the rate is not supported
+        * now it goes to 96Khz */
+       while ((rate_reg_info[count].sample_rate != rate) &&
+              (count < (NUMBER_SAMPLE_RATES_SUPPORTED - 1))) {
+               count++;
+       }
+
+       data = (rate_reg_info[count].divider << CLKIN_SHIFT) |
+           (rate_reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON;
+
+       audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data);
+}
+
+inline void aic23_configure(void)
+{
+       /* Reset codec */
+       audio_aic23_write(RESET_CONTROL_ADDR, 0);
+
+       /* Initialize the AIC23 internal state */
+
+       /*
+        * Analog audio path control, DAC selected,
+        * delete INSEL_MIC for line-in
+        */
+       audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR,
+                               DEFAULT_ANALOG_AUDIO_CONTROL);
+
+       /* Digital audio path control, de-emphasis control 44.1kHz */
+       audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K);
+
+       /* Digital audio interface, master/slave mode, I2S, 16 bit */
+#ifdef AIC23_MASTER
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR,
+                         MS_MASTER | IWL_16 | FOR_DSP);
+#else
+       audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP);
+#endif
+
+       /* Enable digital interface */
+       audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
+}
+
+/*
+ *  OMAP MCBSP clock configuration and Power Management
+ *
+ *  Here we have some functions that allow clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration
+ *   it allows turn on/turn off audio when necessary.
+ */
+/*
+ * Do clock framework mclk search
+ */
+void aic23_clock_setup(void)
+{
+       aic23_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and
+ *  turn codec audio on
+ */
+int aic23_clock_on(void)
+{
+       uint    curRate;
+
+       if (clk_get_usecount(aic23_mclk) > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(aic23_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(aic23_mclk);
+       if (curRate != CODEC_CLOCK) {
+               if (clk_set_rate(aic23_mclk, CODEC_CLOCK)) {
+                       printk(KERN_ERR
+                              "Cannot set MCLK for AIC23 CODEC\n");
+                       return -ECANCELED;
+               }
+       }
+       clk_enable(aic23_mclk);
+
+       printk(KERN_DEBUG
+               "MCLK = %d [%d], usecount = %d\n",
+              (uint) clk_get_rate(aic23_mclk), CODEC_CLOCK,
+              clk_get_usecount(aic23_mclk));
+
+       /* Now turn the audio on */
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+                         ~DEVICE_POWER_OFF & ~OUT_OFF & ~DAC_OFF &
+                         ~ADC_OFF & ~MIC_OFF & ~LINE_OFF);
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn
+ *  codec audio off
+ */
+int aic23_clock_off(void)
+{
+       if (clk_get_usecount(aic23_mclk) > 0) {
+               if (clk_get_rate(aic23_mclk) != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(aic23_mclk),
+                              CODEC_CLOCK);
+               }
+
+               clk_disable(aic23_mclk);
+       }
+
+       audio_aic23_write(POWER_DOWN_CONTROL_ADDR,
+                         DEVICE_POWER_OFF | OUT_OFF | DAC_OFF |
+                         ADC_OFF | MIC_OFF | LINE_OFF);
+       return 0;
+}
+
+int aic23_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_aic23_probe(struct platform_device *pdev)
+{
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates = &aic23_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback =
+                                               &aic23_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture = &aic23_snd_omap_alsa_capture;
+               codec_cfg->codec_configure_dev  = aic23_configure;
+               codec_cfg->codec_set_samplerate = aic23_set_samplerate;
+               codec_cfg->codec_clock_setup    = aic23_clock_setup;
+               codec_cfg->codec_clock_on       = aic23_clock_on;
+               codec_cfg->codec_clock_off      = aic23_clock_off;
+               codec_cfg->get_default_samplerate =
+                                               aic23_get_default_samplerate;
+               ret     = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       } else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_aic23_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_aic23_init(void)
+{
+       int err;
+
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_aic23_exit(void)
+{
+       ADEBUG();
+
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_aic23_init);
+module_exit(omap_alsa_aic23_exit);
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..5431b02
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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 <mach/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <mach/mcbsp.h>
+
+/* Define to set the AIC23 as the master w.r.t McBSP */
+#define AIC23_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  10
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+#define CODEC_CLOCK                    12000000
+#define AUDIO_MCBSP                    OMAP_MCBSP1
+
+#define DEFAULT_OUTPUT_VOLUME          0x60
+#define DEFAULT_INPUT_VOLUME           0x00    /* 0 ==> mute line in */
+
+#define OUTPUT_VOLUME_MIN              LHV_MIN
+#define OUTPUT_VOLUME_MAX              LHV_MAX
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
+#define OUTPUT_VOLUME_MASK             OUTPUT_VOLUME_MAX
+
+#define INPUT_VOLUME_MIN               LIV_MIN
+#define INPUT_VOLUME_MAX               LIV_MAX
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+#define INPUT_VOLUME_MASK              INPUT_VOLUME_MAX
+
+#define SIDETONE_MASK                  0x1c0
+#define SIDETONE_0                     0x100
+#define SIDETONE_6                     0x000
+#define SIDETONE_9                     0x040
+#define SIDETONE_12                    0x080
+#define SIDETONE_18                    0x0c0
+
+#define DEFAULT_ANALOG_AUDIO_CONTROL  (DAC_SELECTED | STE_ENABLED | \
+                                       BYPASS_ON | INSEL_MIC | MICB_20DB)
+
+struct aic23_samplerate_reg_info {
+       u32 sample_rate;
+       u8 control;             /* SR3, SR2, SR1, SR0 and BOSR */
+       u8 divider;             /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */
+};
+
+extern int aic23_write_value(u8 reg, u16 value);
+
+/*
+ * Defines codec specific function pointers that can be used from the
+ * common omap-alsa base driver for all omap codecs. (tsc2101 and aic23)
+ */
+void audio_aic23_write(u8 address, u16 data);
+void define_codec_functions(struct omap_alsa_codec_config *codec_config);
+inline void aic23_configure(void);
+void aic23_set_samplerate(long rate);
+void aic23_clock_setup(void);
+int aic23_clock_on(void);
+int aic23_clock_off(void);
+int aic23_get_default_samplerate(void);
+
+#endif
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..b2623cb
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * sound/arm/omap/omap-alsa-dma.c
+ *
+ * Common audio DMA handling for the OMAP processors
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * 2004-06-07  Sriram Kannan   - Created new file from omap_audio_dma_intfc.c.
+ *                             This file will contain only the DMA interface
+ *                             and buffer handling of OMAP audio driver.
+ *
+ * 2004-06-22  Sriram Kannan   - removed legacy code (auto-init). Self-linking
+ *                             of DMA logical channel.
+ *
+ * 2004-08-12   Nishanth Menon  - Modified to integrate Audio requirements on
+ *                             1610, 1710 platforms
+ *
+ * 2004-11-01   Nishanth Menon  - 16xx platform code base modified to support
+ *                             multi channel chaining.
+ *
+ * 2004-12-15   Nishanth Menon  - Improved 16xx platform channel logic
+ *                             introduced - tasklets, queue handling updated
+ *
+ * 2005-07-19  INdT Kernel Team - Alsa port. Creation of new file
+ *                             omap-alsa-dma.c based in omap-audio-dma-intfc.c
+ *                             oss file. Support for aic23 codec. Removal of
+ *                             buffer handling (Alsa does that), modifications
+ *                             in dma handling and port to alsa structures.
+ *
+ * 2005-12-18   Dirk Behme      - Added L/R Channel Interchange fix as proposed
+ *                             by Ajaya Babu
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/pm.h>
+#include <linux/errno.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/sysrq.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/semaphore.h>
+
+#include <mach/hardware.h>
+#include <mach/dma.h>
+#include <mach/mcbsp.h>
+#include <mach/omap-alsa.h>
+
+#include "omap-alsa-dma.h"
+
+#undef DEBUG
+
+/*
+ * Channel Queue Handling macros
+ * tail always points to the current free entry
+ * Head always points to the current entry being used
+ * end is either head or tail
+ */
+
+#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
+#define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
+#define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
+#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
+#define __AUDIO_INCREMENT_QUEUE(end) ((end) = ((end)+1) % nr_linked_channels)
+#define AUDIO_INCREMENT_HEAD(s)                        \
+       do {                                            \
+               __AUDIO_INCREMENT_QUEUE(s->dma_q_head); \
+               s->dma_q_count--;                       \
+       } while (0)
+#define AUDIO_INCREMENT_TAIL(s)                                \
+       do {                                            \
+               __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); \
+               s->dma_q_count++;                       \
+       } while (0)
+
+/* DMA buffer fragmentation sizes */
+#define MAX_DMA_SIZE            0x1000000 /* todo: sync with alsa */
+/* #define CUT_DMA_SIZE                 0x1000 */
+/* TODO: To be moved to more appropriate location */
+#define DCSR_ERROR           0x3
+#define DCSR_END_BLOCK       (1 << 5)
+#define DCSR_SYNC_SET        (1 << 6)
+
+#define DCCR_FS              (1 << 5)
+#define DCCR_PRIO            (1 << 6)
+#define DCCR_AI              (1 << 8)
+#define DCCR_REPEAT          (1 << 9)
+/* if 0 the channel works in 3.1 compatible mode */
+#define DCCR_N31COMP         (1 << 10)
+#define DCCR_EP              (1 << 11)
+#define DCCR_SRC_AMODE_BIT   12
+#define DCCR_SRC_AMODE_MASK  (0x3<<12)
+#define DCCR_DST_AMODE_BIT   14
+#define DCCR_DST_AMODE_MASK  (0x3<<14)
+#define AMODE_CONST          0x0
+#define AMODE_POST_INC       0x1
+#define AMODE_SINGLE_INDEX   0x2
+#define AMODE_DOUBLE_INDEX   0x3
+
+/* Data structures */
+DEFINE_SPINLOCK(dma_list_lock);
+static char nr_linked_channels = 1;
+
+/* Module specific functions */
+
+static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size);
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size);
+static int audio_start_dma_chain(struct audio_stream *s);
+
+/*
+ * DMA channel requests
+ */
+static void omap_sound_dma_link_lch(void *data)
+{
+
+       struct audio_stream *s = (struct audio_stream *) data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_link_lch(cur_chan, nex_chan);
+       }
+       s->linked = 1;
+       FN_OUT(0);
+}
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                          void *data, int **channels)
+{
+       int i, err = 0;
+       int *chan = NULL;
+       FN_IN;
+       if (unlikely((NULL == channels) || (NULL == device_name))) {
+               BUG();
+               return -EPERM;
+       }
+       /* Try allocate memory for the num channels */
+       *channels = kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
+       chan = *channels;
+       if (NULL == chan) {
+               ERR("No Memory for channel allocs!\n");
+               FN_OUT(-ENOMEM);
+               return -ENOMEM;
+       }
+       spin_lock(&dma_list_lock);
+       for (i = 0; i < nr_linked_channels; i++) {
+               err = omap_request_dma(device_id,
+                               device_name,
+                               sound_dma_irq_handler,
+                               data,
+                               &chan[i]);
+
+               /* Handle Failure condition here */
+               if (err < 0) {
+                       int j;
+
+                       for (j = 0; j < i; j++)
+                               omap_free_dma(chan[j]);
+
+                       spin_unlock(&dma_list_lock);
+                       kfree(chan);
+                       *channels = NULL;
+                       ERR("Error in requesting channel %d=0x%x\n", i,
+                           err);
+                       FN_OUT(err);
+                       return err;
+               }
+       }
+
+       /* Chain the channels together */
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_link_lch(data);
+
+       spin_unlock(&dma_list_lock);
+       FN_OUT(0);
+       return 0;
+}
+EXPORT_SYMBOL(omap_request_alsa_sound_dma);
+
+/*
+ * DMA channel requests Freeing
+ */
+static void omap_sound_dma_unlink_lch(void *data)
+{
+       struct audio_stream *s = (struct audio_stream *)data;
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (!s->linked) {
+               FN_OUT(1);
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               int nex_chan =
+                   ((nr_linked_channels - 1 ==
+                     i) ? chan[0] : chan[i + 1]);
+               omap_dma_unlink_lch(cur_chan, nex_chan);
+       }
+       s->linked = 0;
+       FN_OUT(0);
+}
+
+int omap_free_alsa_sound_dma(void *data, int **channels)
+{
+       int i;
+       int *chan = NULL;
+
+       FN_IN;
+       if (unlikely(NULL == channels)) {
+               BUG();
+               return -EPERM;
+       }
+       if (unlikely(NULL == *channels)) {
+               BUG();
+               return -EPERM;
+       }
+       chan = (*channels);
+
+       if (!cpu_is_omap15xx())
+               omap_sound_dma_unlink_lch(data);
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+               omap_free_dma(cur_chan);
+       }
+       kfree(*channels);
+       *channels = NULL;
+       FN_OUT(0);
+       return 0;
+}
+EXPORT_SYMBOL(omap_free_alsa_sound_dma);
+
+/*
+ * Stop all the DMA channels of the stream
+ */
+void omap_stop_alsa_sound_dma(struct audio_stream *s)
+{
+       int *chan = s->lch;
+       int i;
+
+       FN_IN;
+       if (unlikely(NULL == chan)) {
+               BUG();
+               return;
+       }
+       for (i = 0; i < nr_linked_channels; i++) {
+               int cur_chan = chan[i];
+               omap_stop_dma(cur_chan);
+       }
+       s->started = 0;
+       FN_OUT(0);
+       return;
+}
+EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
+
+/*
+ * Clear any pending transfers
+ */
+void omap_clear_alsa_sound_dma(struct audio_stream *s)
+{
+       FN_IN;
+       omap_clear_dma(s->lch[s->dma_q_head]);
+       FN_OUT(0);
+       return;
+}
+EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
+
+/*
+ * DMA related functions
+ */
+static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
+                                    u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* Stereo */
+       int cfn = dma_size / (2 * cen);
+
+       FN_IN;
+       omap_set_dma_dest_params(channel, 0x05, 0x00,
+                                (OMAP1510_MCBSP1_BASE + 0x06),
+                                0, 0);
+       omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
+                               0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
+                                       u_int dma_size)
+{
+       int dt = 0x1;           /* data type 16 */
+       int cen = 32;           /* stereo */
+       int cfn = dma_size / (2 * cen);
+
+       FN_IN;
+       omap_set_dma_src_params(channel, 0x05, 0x00,
+                               (OMAP1510_MCBSP1_BASE + 0x02),
+                               0, 0);
+       omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
+       omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
+       FN_OUT(0);
+       return 0;
+}
+
+static int audio_start_dma_chain(struct audio_stream *s)
+{
+       int channel = s->lch[s->dma_q_head];
+       FN_IN;
+       if (!s->started) {
+               s->hw_stop();      /* stops McBSP Interface */
+               omap_start_dma(channel);
+               s->started = 1;
+               s->hw_start();     /* start McBSP interface */
+       } else if (cpu_is_omap310())
+               omap_start_dma(channel);
+       /* else the dma itself will progress forward with out our help */
+       FN_OUT(0);
+       return 0;
+}
+
+/*
+ * Start DMA -
+ * Do the initial set of work to initialize all the channels as required.
+ * We shall then initate a transfer
+ */
+int omap_start_alsa_sound_dma(struct audio_stream *s,
+                       dma_addr_t dma_ptr,
+                       u_int dma_size)
+{
+       int ret = -EPERM;
+
+       FN_IN;
+
+       if (unlikely(dma_size > MAX_DMA_SIZE)) {
+               ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
+                   MAX_DMA_SIZE);
+               return -EOVERFLOW;
+       }
+
+       if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* playback */
+               ret =
+                   audio_set_dma_params_play(s->lch[s->dma_q_tail],
+                                             dma_ptr, dma_size);
+       } else {
+               ret =
+                   audio_set_dma_params_capture(s->lch[s->dma_q_tail],
+                                                dma_ptr, dma_size);
+       }
+       if (ret != 0) {
+               ret = -3;       /* indicate queue full */
+               goto sound_out;
+       }
+       AUDIO_INCREMENT_TAIL(s);
+       ret = audio_start_dma_chain(s);
+       if (ret)
+               ERR("dma start failed");
+
+sound_out:
+       FN_OUT(ret);
+       return ret;
+
+}
+EXPORT_SYMBOL(omap_start_alsa_sound_dma);
+
+/*
+ * ISRs have to be short and smart..
+ * Here we call alsa handling, after some error checking
+ */
+static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
+                                 void *data)
+{
+       int dma_status = ch_status;
+       struct audio_stream *s = (struct audio_stream *) data;
+       FN_IN;
+
+       /* some register checking */
+       DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
+               sound_curr_lch, ch_status, dma_status, data);
+
+       if (dma_status & (DCSR_ERROR)) {
+               omap_stop_dma(sound_curr_lch);
+               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");
+
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..0dcd379
--- /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
+
+#include <mach/omap-alsa.h>
+
+/* Global data structures */
+
+typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data);
+
+/* arch specific functions */
+
+void omap_clear_alsa_sound_dma(struct audio_stream *s);
+
+int omap_request_alsa_sound_dma(int device_id, const char *device_name,
+                               void *data, int **channels);
+int omap_free_alsa_sound_dma(void *data, int **channels);
+
+int omap_start_alsa_sound_dma(struct audio_stream *s, dma_addr_t dma_ptr,
+                               u_int dma_size);
+
+void omap_stop_alsa_sound_dma(struct audio_stream *s);
+
+#endif
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..d0c3322
--- /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..7d55388
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * sound/arm/omap/omap-alsa-sx1-mixer.h
+ *
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101-mixer.c
+ *
+ *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef OMAPALSASX1MIXER_H_
+#define OMAPALSASX1MIXER_H_
+
+#include "omap-alsa-dma.h"
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/* following are used for register 03h Mixer PGA control bits
+   D7-D5 for selecting record source */
+#define REC_SRC_TARGET_COUNT           0x08
+/* OSS code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
+/* OSS code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+#define DEFAULT_OUTPUT_VOLUME 5        /* default output volume to dac dgc */
+#define DEFAULT_INPUT_VOLUME  2        /* default record volume */
+
+#endif
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..6253043
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Alsa codec Driver for Siemens SX1 board.
+ * based on omap-alsa-tsc2101.c        and cn_test.c example by Evgeniy Polyakov
+ *
+ * Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/connector.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+
+#include <mach/dma.h>
+#include <mach/clock.h>
+#include <mach/gpio.h>
+#include <mach/mcbsp.h>
+#include <mach/omap-alsa.h>
+
+#include "omap-alsa-sx1.h"
+
+/* Connector implementation */
+static struct cb_id cn_sx1snd_id = { CN_IDX_SX1SND, CN_VAL_SX1SND };
+static char cn_sx1snd_name[] = "cn_sx1snd";
+
+static void cn_sx1snd_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+
+       printk(KERN_INFO
+               "%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+               __func__, jiffies, msg->id.idx, msg->id.val,
+               msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+/* Send IPC message to sound server */
+int cn_sx1snd_send(unsigned int cmd, unsigned int arg1, unsigned int arg2)
+{
+       struct cn_msg *m;
+       unsigned short data[3];
+       int err;
+
+       m = kzalloc(sizeof(*m) + sizeof(data), gfp_any());
+       if (!m)
+               return -1;
+
+       memcpy(&m->id, &cn_sx1snd_id, sizeof(m->id));
+       m->seq = 1;
+       m->len = sizeof(data);
+
+       data[0] = (unsigned short)cmd;
+       data[1] = (unsigned short)arg1;
+       data[2] = (unsigned short)arg2;
+
+       memcpy(m + 1, data, m->len);
+
+       err = cn_netlink_send(m, CN_IDX_SX1SND, gfp_any());
+       snd_printd("sent= %02X %02X %02X, err=%d\n", cmd, arg1, arg2, err);
+       kfree(m);
+
+       if (err == -ESRCH)
+               return -1;      /* there are no listeners on socket */
+       return 0;
+}
+
+/* Hardware capabilities
+ *
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+        8000, 11025, 12000,
+        16000, 22050, 24000,
+        32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list egold_hw_constraints_rates = {
+       .count  = ARRAY_SIZE(rates),
+       .list   = rates,
+       .mask   = 0,
+};
+
+static struct snd_pcm_hardware egold_snd_omap_alsa_playback = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static struct snd_pcm_hardware egold_snd_omap_alsa_capture = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+       .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT),
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+static long current_rate = -1; /* current rate in egold format 0..8 */
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+static void egold_set_samplerate(long sample_rate)
+{
+       int egold_rate = 0;
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       /* Set the sample rate */
+#if 0
+       /* fw15: 5005E490 - divs are different !!! */
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+#endif
+       switch (sample_rate) {
+       case 8000:
+               clkgdv = 71;
+               egold_rate = FRQ_8000;
+               break;
+       case 11025:
+               clkgdv = 51;
+               egold_rate = FRQ_11025;
+               break;
+       case 12000:
+               clkgdv = 47;
+               egold_rate = FRQ_12000;
+               break;
+       case 16000:
+               clkgdv = 35;
+               egold_rate = FRQ_16000;
+               break;
+       case 22050:
+               clkgdv = 25;
+               egold_rate = FRQ_22050;
+               break;
+       case 24000:
+               clkgdv = 23;
+               egold_rate = FRQ_24000;
+               break;
+       case 32000:
+               clkgdv = 17;
+               egold_rate = FRQ_32000;
+               break;
+       case 44100:
+               clkgdv = 12;
+               egold_rate = FRQ_44100;
+               break;
+       case 48000:
+               clkgdv = 11;
+               egold_rate = FRQ_48000;
+               break;
+       }
+
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = egold_rate;
+       snd_printd("set samplerate=%ld\n", sample_rate);
+
+}
+
+static void egold_configure(void)
+{
+}
+
+/*
+ * Omap MCBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allows clock to be enabled and
+ * disabled only when needed. Besides doing clock configuration
+ * it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+static void egold_clock_setup(void)
+{
+       omap_request_gpio(OSC_EN);
+       omap_set_gpio_direction(OSC_EN, 0); /* output */
+       snd_printd("\n");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+static int egold_clock_on(void)
+{
+       omap_set_gpio_dataout(OSC_EN, 1);
+       egold_set_samplerate(44100); /* TODO */
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
+       cn_sx1snd_send(DAC_OPEN_DEFAULT, current_rate , 4);
+       snd_printd("\n");
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+static int egold_clock_off(void)
+{
+       cn_sx1snd_send(DAC_CLOSE, 0 , 0);
+       cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
+       omap_set_gpio_dataout(OSC_EN, 0);
+       snd_printd("\n");
+       return 0;
+}
+
+static int egold_get_default_samplerate(void)
+{
+       snd_printd("\n");
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __init snd_omap_alsa_egold_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg;
+
+       codec_cfg = pdev->dev.platform_data;
+       if (!codec_cfg)
+               return -ENODEV;
+
+       codec_cfg->hw_constraints_rates = &egold_hw_constraints_rates;
+       codec_cfg->snd_omap_alsa_playback = &egold_snd_omap_alsa_playback;
+       codec_cfg->snd_omap_alsa_capture = &egold_snd_omap_alsa_capture;
+       codec_cfg->codec_configure_dev  = egold_configure;
+       codec_cfg->codec_set_samplerate = egold_set_samplerate;
+       codec_cfg->codec_clock_setup    = egold_clock_setup;
+       codec_cfg->codec_clock_on       = egold_clock_on;
+       codec_cfg->codec_clock_off      = egold_clock_off;
+       codec_cfg->get_default_samplerate = egold_get_default_samplerate;
+       ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+
+       snd_printd("\n");
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_egold_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_egold_init(void)
+{
+       int retval;
+
+       retval = cn_add_callback(&cn_sx1snd_id, cn_sx1snd_name,
+                                       cn_sx1snd_callback);
+       if (retval)
+               printk(KERN_WARNING "cn_sx1snd failed to register\n");
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_egold_exit(void)
+{
+       cn_del_callback(&cn_sx1snd_id);
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_egold_init);
+module_exit(omap_alsa_egold_exit);
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..9e11e0a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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..d443342
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.c
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Board initialization code is based on the code in TSC2101 OSS driver.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback,
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control
+ *             are still missing.
+ *
+ */
+
+#include "omap-alsa-tsc2101.h"
+#include "omap-alsa-tsc2101-mixer.h"
+
+#include <linux/spi/tsc2101.h>
+#include <linux/types.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#ifdef DEBUG
+#define M_DPRINTK(ARGS...)                             \
+       do {                                            \
+               printk(KERN_INFO "<%s>: ", __func__);   \
+               printk(ARGS);                           \
+       } while (0)
+#else
+#define M_DPRINTK(ARGS...)             /* nop */
+#endif
+
+#define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
+#define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
+
+#define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
+
+#define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+#define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
+
+static int current_playback_target     = PLAYBACK_TARGET_LOUDSPEAKER;
+static int current_rec_src             = REC_SRC_SINGLE_ENDED_MICIN_HED;
+
+/*
+ * Simplified write for the tsc2101 audio registers.
+ */
+inline void omap_tsc2101_audio_write(u8 address, u16 data)
+{
+       tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+                               address, data);
+}
+
+/*
+ * Simplified read for the tsc2101 audio registers.
+ */
+inline u16 omap_tsc2101_audio_read(u8 address)
+{
+       return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
+                                       PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+/*
+ * For selecting tsc2101 recourd source.
+ */
+static void set_record_source(int val)
+{
+       u16     data;
+
+       /*
+        * Mute Analog Sidetone
+        * Analog sidetone gain db?
+        * Input selected by MICSEL connected to ADC
+        */
+       data    = MPC_ASTMU | MPC_ASTG(0x45);
+       data    &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
+       data    |= MPC_MICSEL(val);
+       data    |= MPC_MICADC;
+       omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
+
+       current_rec_src = val;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to real
+ * Digital Gain Control (DGC) value that can be written
+ * or read from the TSC2101 registry.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
+ * because DGC works as a volume decreaser. (The more bigger value is put
+ * to DGC, the more the volume of controlled channel is decreased)
+ *
+ * In addition the TCS2101 chip would allow the maximum
+ * volume reduction be 63.5 DB
+ * but according to some tests user can not hear anything with this chip
+ * when the volume is set to be less than 25 db.
+ * Therefore this function will return a value
+ * that means 38.5 db (63.5 db - 25 db)
+ * reduction in the channel volume, when mixer is set to 0.
+ * For mixer value 100, this will return a value that means
+ * 0 db volume reduction.
+ * ([mute_left_bit]0000000[mute_right_bit]0000000)
+ */
+int get_mixer_volume_as_dac_gain_control_volume(int vol)
+{
+       u16 retVal;
+
+       /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
+       retVal = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
+       /* invert the value for getting the proper range 0 min and 100 max */
+       retVal = OUTPUT_VOLUME_MIN - retVal;
+
+       return retVal;
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to TSC2101
+ * Digital Gain Control (DGC) volume. Alsa mixer volume 0
+ * is converted to value meaning the volume reduction of -38.5 db
+ * and Alsa mixer volume 100 is converted to value meaning the
+ * reduction of 0 db.
+ */
+int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR)
+{
+       u16 val;
+       int retVal;
+       int volL;
+       int volR;
+
+       if ((mixerVolL < 0) ||
+           (mixerVolL > 100) ||
+           (mixerVolR < 0) ||
+           (mixerVolR > 100)) {
+               printk(KERN_ERR "Trying a bad mixer volume as dac gain control"
+                       " volume value, left (%d), right (%d)!\n", mixerVolL,
+                       mixerVolR);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);
+       volL    = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
+       volR    = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
+
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /* keep the old mute bit settings */
+       val     &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) |
+                       DGC_DARVL(OUTPUT_VOLUME_MIN));
+       val     |= DGC_DALVL(volL) | DGC_DARVL(volR);
+       retVal  = 2;
+       if (retVal)
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+
+       M_DPRINTK("to registry: left = %d, right = %d, total = %d\n",
+                       DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
+       return retVal;
+}
+
+/*
+ * If unmuteLeft/unmuteRight == 0  --> mute
+ * If unmuteLeft/unmuteRight == 1 --> unmute
+ */
+int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
+{
+       u16 val;
+       int count;
+
+       count   = 0;
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       /*
+        * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
+        * 0 --> on so if values are same, it's time to change the registry
+        * value.
+        */
+       if (unmuteLeft != IS_UNMUTED(15, val)) {
+               if (unmuteLeft == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DALMU;
+               } else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DALMU;
+               }
+               count++;
+       } /* L */
+       if (unmuteRight != IS_UNMUTED(7, val)) {
+               if (unmuteRight == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | DGC_DARMU;
+               } else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~DGC_DARMU;
+               }
+               count++;
+       } /* R */
+       if (count) {
+               omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+               M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n",
+                       IS_UNMUTED(15, val),
+                       IS_UNMUTED(7, val));
+       }
+       return count;
+}
+
+/*
+ * unmute: 0 --> mute, 1 --> unmute
+ * page2RegIndx: Registry index in tsc2101 page2.
+ * muteBitIndx: Index number for the bit in registry that indicates whether
+ * muted or unmuted.
+ */
+int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
+{
+       int count;
+       u16 val;
+
+       count   = 0;
+       val     = omap_tsc2101_audio_read(page2regIndx);
+       /*
+        * in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off,
+        * 0 --> on so if the values are same, it's time to change the
+        * registry value...
+        */
+       if (unmute != IS_UNMUTED(muteBitIndx, val)) {
+               if (unmute == 0) {
+                       /* mute --> turn bit on */
+                       val     = val | TSC2101_BIT(muteBitIndx);
+               } else {
+                       /* unmute --> turn bit off */
+                       val     = val & ~TSC2101_BIT(muteBitIndx);
+               }
+               M_DPRINTK("changed value, is_unmuted = %d\n",
+                               IS_UNMUTED(muteBitIndx, val));
+               count++;
+       }
+       if (count)
+               omap_tsc2101_audio_write(page2regIndx, val);
+
+       return count;
+}
+
+/*
+ * Converts the DGC registry value read from the TSC2101 registry to
+ * Alsa mixer volume format (0 - 100).
+ */
+int get_dac_gain_control_volume_as_mixer_volume(u16 vol)
+{
+       u16 retVal;
+
+       retVal  = OUTPUT_VOLUME_MIN - vol;
+       retVal  = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
+       /* fix scaling error */
+       if ((retVal > 0) && (retVal < 100))
+               retVal++;
+
+       return retVal;
+}
+
+/*
+ * Converts the headset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal)
+{
+       u16 retVal;
+
+       retVal  = ((registerVal * 100) / INPUT_VOLUME_RANGE);
+       return retVal;
+}
+
+/*
+ * Converts the handset gain control volume (0 - 63.5 db)
+ * to Alsa mixer volume (0 - 100)
+ */
+int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal)
+{
+       return get_headset_gain_control_volume_as_mixer_volume(registerVal);
+}
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to
+ * headset gain control volume (0 - 63.5 db)
+ */
+int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal)
+{
+       u16 retVal;
+
+       retVal  = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with "SET_LINE"
+ * parameter.
+ */
+int set_mixer_volume_as_headset_gain_control_volume(int mixerVol)
+{
+       int volume;
+       int retVal;
+       u16 val;
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n",
+                               mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /*
+        * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+        * NOTE: 0 is minimum volume and not mute
+        */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       /* preserve the old mute settings */
+       val     &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
+       val     |= HGC_ADPGA_HED(volume);
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+       retVal  = 1;
+
+       M_DPRINTK("to registry = %d\n", val);
+       return retVal;
+}
+
+/*
+ * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
+ * a TSC2101 format. (0 - 63.5 db)
+ * In TSC2101 OSS driver this functionality was controlled with
+ * "SET_MIC" parameter.
+ */
+int set_mixer_volume_as_handset_gain_control_volume(int mixerVol)
+{
+       int volume;
+       int retVal;
+       u16 val;
+
+       if (mixerVol < 0 || mixerVol > 100) {
+               M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n",
+                               mixerVol);
+               return -EPERM;
+       }
+       M_DPRINTK("mixer volume = %d\n", mixerVol);
+       /*
+        * Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
+        * NOTE: 0 is minimum volume and not mute
+        */
+       volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       /* preserve the old mute settigns */
+       val     &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
+       val     |= HNGC_ADPGA_HND(volume);
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+       retVal  = 1;
+
+       M_DPRINTK("to registry = %d\n", val);
+       return retVal;
+}
+
+void set_loudspeaker_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+       /*
+        * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /*
+        * DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DIFFIN |
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
+
+       /*
+        * routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
+        * analog sidetone routed to loudspeaker
+        * buzzer pga routed to loudspeaker
+        * keyclick routing to loudspeaker
+        * cellphone input routed to loudspeaker
+        * mic selection (control register 04h/page2) routed to cell phone
+        * output (CP_OUT)
+        * routing selected for SPK1 goes also to cellphone output (CP_OUT)
+        * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
+        * Cellphone output is not muted (0 = unmuted)
+        * Enable loudspeaker short protection control (0 = enable protection)
+        * VGND short protection control (0 = enable protection)
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
+                       AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
+       current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
+}
+
+void set_headphone_to_playback_target(void)
+{
+       /* power down SPK1, SPK2 and loudspeaker */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
+       /*
+        * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+       Â * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
+
+       /*
+        * DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * Keyclicks routed to SPK1/SPK2
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
+                       AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
+                       AC5_HDSCPTC);
+
+       /* OUT8P/OUT8N muted, CPOUT muted */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
+                       AC6_VGNDSCPTC);
+       current_playback_target = PLAYBACK_TARGET_HEADPHONE;
+}
+
+void set_telephone_to_playback_target(void)
+{
+       /*
+        * 0110 1101 0101 1100
+        * power down MICBIAS_HED, Analog sidetone, SPK2, DAC,
+        * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
+        */
+       omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                       CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
+                       CPC_VGPWDN | CPC_LSPWDN);
+
+       /*
+        * 0010 1010 0100 0000
+        * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
+        * 1dB AGC hysteresis
+        * MICes bias 2V
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
+                       AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) |
+                       AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
+       printk(KERN_INFO "set_telephone_to_playback_target(), "
+                       "TSC2101_AUDIO_CTRL_4 = %d\n",
+                       omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+
+       /*
+        * 1110 0010 0000 0010
+        * DAC left and right routed to SPK1/SPK2
+        * SPK1/SPK2 unmuted
+        * keyclicks routed to SPK1/SPK2
+        */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
+                       AC5_DIFFIN | AC5_DAC2SPK1(3) |
+                       AC5_CPI2SPK1 | AC5_MUTSPK2);
+
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
+                       AC6_MIC2CPO | AC6_MUTLSPK |
+                       AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
+       current_playback_target = PLAYBACK_TARGET_CELLPHONE;
+}
+
+/*
+ * 1100 0101 1101 0000
+ *
+ * #define MPC_ASTMU           TSC2101_BIT(15)
+ * #define MPC_ASTG(ARG)       (((ARG) & 0x7F) << 8)
+ * #define MPC_MICSEL(ARG)     (((ARG) & 0x07) << 5)
+ * #define MPC_MICADC          TSC2101_BIT(4)
+ * #define MPC_CPADC           TSC2101_BIT(3)
+ * #define MPC_ASTGF           (0x01)
+ */
+static void set_telephone_to_record_source(void)
+{
+       u16     val;
+
+       /*
+        * D0       = 0:
+        *              --> AGC is off for handset input.
+        *              --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
+        *          (D15, D14-D8)
+        * D4 - D1  = 0000
+        *              --> AGC time constant for handset input,
+        *              attack time = 8 mc, decay time = 100 ms
+        * D7 - D5  = 000
+        *              --> AGC Target gain for handset input = -5.5 db
+        * D14 - D8 = 011 1100
+        *              --> ADC handset PGA settings = 60 = 30 db
+        * D15          = 0
+        *              --> Handset input ON (unmuted)
+        */
+       val     = 0x3c00;       /* 0011 1100 0000 0000 = 60 = 30 */
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+
+       /*
+        * D0           = 0
+        *              --> AGC is off for headset/Aux input
+        *              --> ADC headset/Aux PGA is contoller by
+        *              ADMUT_HED + ADPGA_HED
+        *          (D15, D14-D8)
+        * D4 - D1      = 0000
+        *              --> Agc constant for headset/Aux input,
+        *              attack time = 8 mc, decay time = 100 ms
+        * D7 - D5      = 000
+        *              --> AGC target gain for headset input = -5.5 db
+        * D14 - D8 = 000 0000
+        *              --> Adc headset/AUX pga settings = 0 db
+        * D15          = 1
+        *              --> Headset/AUX input muted
+        *
+        * Mute headset aux input
+        */
+       val     = 0x8000;       /* 1000 0000 0000 0000 */
+       omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
+       set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
+
+       /*
+        * hacks start
+        * D0           = flag, Headset/Aux or handset PGA flag
+        *              --> & with 1 (= 1 -->gain applied == pga
+        *              register settings)
+        * D1           = 0, DAC channel PGA soft stepping control
+        *              --> 0.5 db change every WCLK
+        * D2           = flag, DAC right channel PGA flag
+        *              --> & with 1
+        * D3           = flag, DAC left channel PGA flag
+        *              -- > & with 1
+        * D7 - D4      = 0001, keyclick length
+        *              --> 4 periods key clicks
+        * D10 - D8 = 100, keyclick frequency
+        *              --> 1 kHz,
+        * D11          = 0, Headset/Aux or handset soft stepping control
+        *              --> 0,5 db change every WCLK or ADWS
+        * D14 -D12 = 100, Keyclick applitude control
+        *              --> Medium amplitude
+        * D15          = 0, keyclick disabled
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
+       val     = val & 0x441d;
+       val     = val | 0x4410; /* D14, D10, D4 bits == 1 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
+
+       /*
+        * D0           = 0     (reserved, write always 0)
+        * D1           = flag,
+        *                      --> & with 1
+        * D2 - D5      = 0000 (reserved, write always 0000)
+        * D6           = 1
+        *                      --> MICBIAS_HND = 2.0 v
+        * D8 - D7      = 00
+        *                      --> MICBIAS_HED = 3.3 v
+        * D10 - D9     = 01,
+        *                      --> Mic AGC hysteric selection = 2 db
+        * D11          = 1,
+        *                      --> Disable buzzer PGA soft stepping
+        * D12          = 0,
+        *                      --> Enable CELL phone PGA soft stepping control
+        * D13          = 1
+        *                      --> Disable analog sidetone soft
+        *                      stepping control
+        * D14          = 0
+        *                      --> Enable DAC PGA soft stepping control
+        * D15          = 0,
+        *                      --> Enable headset/Aux or Handset soft
+        *                      stepping control
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
+       val     = val & 0x2a42; /* 0010 1010 0100 0010 */
+       val     = val | 0x2a40; /* bits D13, D11, D9, D6 == 1 */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
+       printk(KERN_INFO "set_telephone_to_record_source(), "
+                       "TSC2101_AUDIO_CTRL_4 = %d\n",
+                       omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       /*
+        * D0           = 0
+        *              --> reserved, write always = 0
+        * D1           = flag, read only
+        *              --> & with 1
+        * D5 - D2      = 1111, Buzzer input PGA settings
+        *              --> 0 db
+        * D6           = 1,
+        *              --> power down buzzer input pga
+        * D7           = flag, read only
+        *              --> & with 1
+        * D14 - D8     = 101 1101
+        *              --> 12 DB
+        * D15          = 0
+        *              --> power up cell phone input PGA
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       val     = val & 0x5dfe;
+       /* bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2 */
+       val     = val | 0x5dfe;
+       omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
+
+       /*
+        * D6 - D0      = 000 1001
+        *              --> -4.5 db for DAC right channel volume control
+        * D7           = 1
+        *              -->  DAC right channel muted
+        * D14 - D8 = 000 1001
+        *              --> -4.5 db for DAC left channel volume control
+        * D15          = 1
+        *              --> DAC left channel muted
+        */
+       /* val  = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL); */
+       val     = 0x8989;
+       omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
+
+       /*
+        *   0000 0000 0100 0000
+        *
+        * D1 - D0      = 0
+        *              --> GPIO 1 pin output is three stated
+        * D2           = 0
+        *              --> Disaple GPIO2 for CLKOUT mode
+        * D3           = 0
+        *              --> Disable GPUI1 for interrupt detection
+        * D4           = 0
+        *              --> Disable GPIO2 for headset detection interrupt
+        * D5           = reserved, always 0
+        * D7 - D6      = 01
+        *              --> 8 ms clitch detection
+        * D8           = reserved, write only 0
+        * D10 -D9      = 00
+        *              --> 16 ms de-bouncing
+        *          for glitch detection during headset detection
+        * D11          = flag for button press
+        * D12          = flag for headset detection
+        * D14-D13      = 00
+        *              --> type of headset detected = 00 == no stereo
+        *              headset deected
+        * D15          = 0
+        *              --> Disable headset detection
+        */
+       val     = 0x40;
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);
+}
+
+/*
+ * Checks whether the headset is detected.
+ * If headset is detected, the type is returned. Type can be
+ *     0x01    = stereo headset detected
+ *     0x02    = cellurar headset detected
+ *     0x03    = stereo + cellurar headset detected
+ * If headset is not detected 0 is returned.
+ */
+u16 get_headset_detected(void)
+{
+       u16     curDetected;
+       u16     curType;
+       u16     curVal;
+
+       curType = 0;    /* not detected */
+       curVal  = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
+       curDetected     = curVal & AC7_HDDETFL;
+       if (curDetected) {
+               printk(KERN_INFO "headset detected, checking type from %d \n",
+                       curVal);
+               curType = ((curVal & 0x6000) >> 13);
+               printk(KERN_INFO "headset type detected = %d \n", curType);
+       } else {
+               printk(KERN_INFO "headset not detected\n");
+       }
+       return curType;
+}
+
+void init_playback_targets(void)
+{
+       u16     val;
+
+       set_loudspeaker_to_playback_target();
+       /*
+        * Left line input volume control
+        * = SET_LINE in the OSS driver
+        */
+       set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /*
+        * Set headset to be controllable by handset mixer
+        * AGC enable for handset input
+        * Handset input not muted
+        */
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       val     = val | HNGC_AGCEN_HND;
+       val     = val & ~HNGC_ADMUT_HND;
+       omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
+
+       /*
+        * mic input volume control
+        * SET_MIC in the OSS driver
+        */
+       set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
+
+       /*
+        * Left/Right headphone channel volume control
+        * Zero-cross detect on
+        */
+       set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME,
+                                                       DEFAULT_OUTPUT_VOLUME);
+       /* unmute */
+       dac_gain_control_unmute(1, 1);
+}
+
+/*
+ * Initializes tsc2101 recourd source (to line) and playback target
+ * (to loudspeaker)
+ */
+void snd_omap_init_mixer(void)
+{
+       FN_IN;
+
+       /* Headset/Hook switch detect enabled */
+       omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
+
+       /* Select headset to record source (MIC_INHED)*/
+       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+       /* Init loudspeaker as a default playback target*/
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_target_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       static char *texts[PLAYBACK_TARGET_COUNT] = {
+               "Loudspeaker", "Headphone", "Cellphone"
+       };
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
+       if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
+               uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
+
+       strcpy(uinfo->value.enumerated.name,
+               texts[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int __pcm_playback_target_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = current_playback_target;
+       return 0;
+}
+
+static int __pcm_playback_target_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       int     retVal;
+       int     curVal;
+
+       retVal  = 0;
+       curVal  = ucontrol->value.integer.value[0];
+       if ((curVal >= 0) &&
+           (curVal < PLAYBACK_TARGET_COUNT) &&
+           (curVal != current_playback_target)) {
+               if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
+                       set_loudspeaker_to_playback_target();
+               } else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
+                       set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
+                       set_headphone_to_playback_target();
+               } else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
+                       set_telephone_to_record_source();
+                       set_telephone_to_playback_target();
+               }
+               retVal  = 1;
+       }
+       return retVal;
+}
+
+static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+/*
+ * Alsa mixer interface function for getting the volume read from the DGC in a
+ * 0 -100 alsa mixer format.
+ */
+static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 volL;
+       u16 volR;
+       u16 val;
+
+       val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+       M_DPRINTK("registry value = %d!\n", val);
+       volL    = DGC_DALVL_EXTRACT(val);
+       volR    = DGC_DARVL_EXTRACT(val);
+       /* make sure that other bits are not on */
+       volL    = volL & ~DGC_DALMU;
+       volR    = volR & ~DGC_DARMU;
+
+       volL    = get_dac_gain_control_volume_as_mixer_volume(volL);
+       volR    = get_dac_gain_control_volume_as_mixer_volume(volR);
+
+       ucontrol->value.integer.value[0]        = volL; /* L */
+       ucontrol->value.integer.value[1]        = volR; /* R */
+
+       M_DPRINTK("mixer volume left = %ld, right = %ld\n",
+                       ucontrol->value.integer.value[0],
+                       ucontrol->value.integer.value[1]);
+       return 0;
+}
+
+static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume_as_dac_gain_control_volume(
+                                       ucontrol->value.integer.value[0],
+                                       ucontrol->value.integer.value[1]);
+}
+
+static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/*
+ * When DGC_DALMU (bit 15) is 1, the left channel is muted.
+ * When DGC_DALMU is 0, left channel is not muted.
+ * Same logic apply also for the right channel.
+ */
+static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
+
+       ucontrol->value.integer.value[0] = IS_UNMUTED(15, val); /* left */
+       ucontrol->value.integer.value[1] = IS_UNMUTED(7, val); /* right */
+       return 0;
+}
+
+static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return dac_gain_control_unmute(ucontrol->value.integer.value[0],
+                                       ucontrol->value.integer.value[1]);
+}
+
+static int __headset_playback_volume_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __headset_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val;
+       u16 vol;
+
+       val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HGC_ADPGA_HED_EXTRACT(val);
+       vol     = vol & ~HGC_ADMUT_HED;
+
+       vol     = get_headset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+
+       M_DPRINTK("mixer volume returned = %ld\n",
+                       ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __headset_playback_volume_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume_as_headset_gain_control_volume(
+                                       ucontrol->value.integer.value[0]);
+}
+
+static int __headset_playback_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/*
+ * When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
+ * When HGC_ADMUT_HED is 0, headset is not muted.
+ */
+static int __headset_playback_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __headset_playback_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       /* mute/unmute headset */
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HEADSET_GAIN_CTRL,
+                               15);
+}
+
+static int __handset_playback_volume_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __handset_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val;
+       u16 vol;
+
+       val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       M_DPRINTK("registry value = %d\n", val);
+       vol     = HNGC_ADPGA_HND_EXTRACT(val);
+       vol     = vol & ~HNGC_ADMUT_HND;
+       vol     = get_handset_gain_control_volume_as_mixer_volume(vol);
+       ucontrol->value.integer.value[0]        = vol;
+
+       M_DPRINTK("mixer volume returned = %ld\n",
+                       ucontrol->value.integer.value[0]);
+       return 0;
+}
+
+static int __handset_playback_volume_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return set_mixer_volume_as_handset_gain_control_volume(
+                                       ucontrol->value.integer.value[0]);
+}
+
+static int __handset_playback_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/*
+ * When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
+ * When HNGC_ADMUT_HND is 0, handset is not muted.
+ */
+static int __handset_playback_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __handset_playback_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       /* handset mute/unmute */
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_HANDSET_GAIN_CTRL,
+                               15);
+}
+
+static int __cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/*
+ * When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
+ * When BGC_MUT_CP = 0, power up cellphone input pga.
+ */
+static int __cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
+       return 0;
+}
+
+static int __cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               15);
+}
+
+static int __buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+/*
+ * When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
+ * When BGC_MUT_BU = 0, power up cellphone input pga.
+ */
+static int __buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
+       ucontrol->value.integer.value[0]        = IS_UNMUTED(6, val);
+       return 0;
+}
+
+static int __buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       return adc_pga_unmute_control(ucontrol->value.integer.value[0],
+                               TSC2101_BUZZER_GAIN_CTRL,
+                               6);
+}
+
+static struct snd_kcontrol_new tsc2101_control[] __devinitdata = {
+       {
+               .name   = "Target Playback Route",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_target_info,
+               .get    = __pcm_playback_target_get,
+               .put    = __pcm_playback_target_put,
+       }, {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_volume_info,
+               .get    = __pcm_playback_volume_get,
+               .put    = __pcm_playback_volume_put,
+       }, {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_switch_info,
+               .get    = __pcm_playback_switch_get,
+               .put    = __pcm_playback_switch_put,
+       }, {
+               .name   = "Headset Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __headset_playback_volume_info,
+               .get    = __headset_playback_volume_get,
+               .put    = __headset_playback_volume_put,
+       }, {
+               .name   = "Headset Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __headset_playback_switch_info,
+               .get    = __headset_playback_switch_get,
+               .put    = __headset_playback_switch_put,
+       }, {
+               .name   = "Handset Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __handset_playback_volume_info,
+               .get    = __handset_playback_volume_get,
+               .put    = __handset_playback_volume_put,
+       }, {
+               .name   = "Handset Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __handset_playback_switch_info,
+               .get    = __handset_playback_switch_get,
+               .put    = __handset_playback_switch_put,
+       }, {
+               .name   = "Cellphone Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __cellphone_input_switch_info,
+               .get    = __cellphone_input_switch_get,
+               .put    = __cellphone_input_switch_put,
+       }, {
+               .name   = "Buzzer Input Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __buzzer_input_switch_info,
+               .get    = __buzzer_input_switch_get,
+               .put    = __buzzer_input_switch_put,
+       }
+};
+
+#ifdef CONFIG_PM
+
+void snd_omap_suspend_mixer(void)
+{
+}
+
+void snd_omap_resume_mixer(void)
+{
+       snd_omap_init_mixer();
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2101)
+{
+       int i = 0;
+       int err = 0;
+
+       if (!tsc2101)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(tsc2101_control); i++) {
+               err = snd_ctl_add(tsc2101->card,
+                                       snd_ctl_new1(&tsc2101_control[i],
+                                       tsc2101->card));
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
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..c0d9b23
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101-mixer.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and
+ *                  Everett Coleman II <gcc80x86@fuzzyneural.net>
+ *
+ * Based on the ideas in omap-aic23.c and sa11xx-uda1341.c
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
+ *             Can switch between headset and loudspeaker playback,
+ *             mute and unmute dgc, set dgc volume. Record source switch,
+ *             keyclick, buzzer and headset volume and handset volume control
+ *             are still missing.
+ */
+
+#ifndef OMAPALSATSC2101MIXER_H_
+#define OMAPALSATSC2101MIXER_H_
+
+#include <asm/hardware/tsc2101.h>
+#include "omap-alsa-dma.h"
+
+/* tsc2101 DAC gain control volume specific  */
+#define OUTPUT_VOLUME_MIN              0x7F    /* 1111111 = -63.5 DB */
+#define OUTPUT_VOLUME_MAX              0x32    /* 110010 */
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+/* use input vol of 75 for 0dB gain */
+#define INPUT_VOLUME_MIN               0x0
+#define INPUT_VOLUME_MAX               0x7D
+#define INPUT_VOLUME_RANGE             (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
+
+#define PLAYBACK_TARGET_COUNT          0x03
+#define PLAYBACK_TARGET_LOUDSPEAKER    0x00
+#define PLAYBACK_TARGET_HEADPHONE      0x01
+#define PLAYBACK_TARGET_CELLPHONE      0x02
+
+/*
+ * Following are used for register 03h Mixer PGA control bits D7-D5 for
+ * selecting record source
+ */
+#define REC_SRC_TARGET_COUNT           0x08
+/* oss code referred to MIXER_LINE */
+#define REC_SRC_SINGLE_ENDED_MICIN_HED 0x00
+/* oss code referred to MIXER_MIC */
+#define REC_SRC_SINGLE_ENDED_MICIN_HND 0x01
+#define REC_SRC_SINGLE_ENDED_AUX1      0x02
+#define REC_SRC_SINGLE_ENDED_AUX2      0x03
+#define REC_SRC_MICIN_HED_AND_AUX1     0x04
+#define REC_SRC_MICIN_HED_AND_AUX2     0x05
+#define REC_SRC_MICIN_HND_AND_AUX1     0x06
+#define REC_SRC_MICIN_HND_AND_AUX2     0x07
+
+/* default output volume to dac dgc */
+#define DEFAULT_OUTPUT_VOLUME          90
+/* default record volume */
+#define DEFAULT_INPUT_VOLUME           20
+
+#define TSC2101_AUDIO_CODEC_REGISTERS_PAGE2     (2)
+
+extern struct mcbsp_dev_info mcbsp_dev;
+
+#endif /*OMAPALSATSC2101MIXER_H_*/
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..6b0e106
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.c
+ *
+ * Alsa codec Driver for TSC2101 chip for OMAP platform boards.
+ * Code obtained from oss omap drivers
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *     Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spi/tsc2101.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <asm/mach-types.h>
+#include <mach/dma.h>
+#include <mach/clock.h>
+#include <mach/mcbsp.h>
+#include <asm/hardware/tsc2101.h>
+#include <mach/omap-alsa.h>
+
+#include "omap-alsa-tsc2101.h"
+
+struct mcbsp_dev_info mcbsp_dev;
+
+static struct clk *tsc2101_mclk;
+
+/* #define DUMP_TSC2101_AUDIO_REGISTERS */
+#undef DUMP_TSC2101_AUDIO_REGISTERS
+
+/*
+ * Hardware capabilities
+ */
+
+/*
+ * DAC USB-mode sampling rates (MCLK = 12 MHz)
+ * The rates and rate_reg_into MUST be in the same order
+ */
+static unsigned int rates[] = {
+       7350, 8000, 8018, 8727,
+       8820, 9600, 11025, 12000,
+       14700, 16000, 22050, 24000,
+       29400, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list tsc2101_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static const struct tsc2101_samplerate_reg_info
+    rate_reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = {
+       /* Div 6 */
+       {7350, 7, 1},
+       {8000, 7, 0},
+       /* Div 5.5 */
+       {8018, 6, 1},
+       {8727, 6, 0},
+       /* Div 5 */
+       {8820, 5, 1},
+       {9600, 5, 0},
+       /* Div 4 */
+       {11025, 4, 1},
+       {12000, 4, 0},
+       /* Div 3 */
+       {14700, 3, 1},
+       {16000, 3, 0},
+       /* Div 2 */
+       {22050, 2, 1},
+       {24000, 2, 0},
+       /* Div 1.5 */
+       {29400, 1, 1},
+       {32000, 1, 0},
+       /* Div 1 */
+       {44100, 0, 1},
+       {48000, 0, 0},
+};
+
+static struct snd_pcm_hardware tsc2101_snd_omap_alsa_playback = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID,
+#ifdef CONFIG_MACH_OMAP_H6300
+       .formats = SNDRV_PCM_FMTBIT_S8,
+#else
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+#endif
+       .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT,
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+static struct snd_pcm_hardware tsc2101_snd_omap_alsa_capture = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+                 SNDRV_PCM_RATE_16000 |
+                 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
+                 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_KNOT,
+       .rate_min = 7350,
+       .rate_max = 48000,
+       .channels_min = 2,
+       .channels_max = 2,
+       .buffer_bytes_max = 128 * 1024,
+       .period_bytes_min = 32,
+       .period_bytes_max = 8 * 1024,
+       .periods_min = 16,
+       .periods_max = 255,
+       .fifo_size = 0,
+};
+
+/*
+ * Simplified write for tsc2101 audio registers.
+ */
+inline void tsc2101_audio_write(u8 address, u16 data)
+{
+       tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+                               address, data);
+}
+
+/*
+ * Simplified read for tsc2101 audio registers.
+ */
+inline u16 tsc2101_audio_read(u8 address)
+{
+       return (tsc2101_read_sync(mcbsp_dev.tsc2101_dev,
+                                       PAGE2_AUDIO_CODEC_REGISTERS, address));
+}
+
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+void dump_tsc2101_audio_reg(void)
+{
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_HEADSET_GAIN_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_DAC_GAIN_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_MIXER_PGA_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_MIXER_PGA_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_2 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_CODEC_POWER_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_CODEC_POWER_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_3 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_3));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N0 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N0));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N2 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N3 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N3));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N4 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N4));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_N5 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_N5));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_D1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_D2 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_D4 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D4));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_LCH_BASS_BOOST_D5 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_LCH_BASS_BOOST_D5));
+
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N0 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N0));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N2 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N3 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N3));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N4 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N4));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_N5 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_N5));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_D1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_D2 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_D4 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D4));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_RCH_BASS_BOOST_D5 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_RCH_BASS_BOOST_D5));
+
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_PLL_PROG_1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_PLL_PROG_1));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_PLL_PROG_1 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_PLL_PROG_2));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_4 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_HANDSET_GAIN_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_BUZZER_GAIN_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_5 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_5));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_6 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_6));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AUDIO_CTRL_7 = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AUDIO_CTRL_7));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_GPIO_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_GPIO_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_AGC_CTRL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_AGC_CTRL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_POWERDOWN_STS = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_POWERDOWN_STS));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_MIC_AGC_CONTROL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_MIC_AGC_CONTROL));
+       dev_dbg(&mcbsp_dev.mcbsp_dev->dev,
+               "TSC2101_CELL_AGC_CONTROL = 0x%04x\n",
+               tsc2101_audio_read(TSC2101_CELL_AGC_CONTROL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+/*
+ * Sample rate changing
+ */
+void tsc2101_set_samplerate(long sample_rate)
+{
+       u8 count = 0;
+       u16 data = 0;
+       int clkgdv = 0;
+
+       u16 srgr1, srgr2;
+       /* wait for any frame to complete */
+       udelay(125);
+       ADEBUG();
+
+       sample_rate     = sample_rate;
+       /* Search for the right sample rate */
+       while ((rate_reg_info[count].sample_rate != sample_rate) &&
+              (count < NUMBER_SAMPLE_RATES_SUPPORTED)) {
+               count++;
+       }
+       if (count == NUMBER_SAMPLE_RATES_SUPPORTED) {
+               printk(KERN_ERR "Invalid Sample Rate %d requested\n",
+                      (int) sample_rate);
+               return;
+       }
+
+       /* Set AC1 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_1);
+       /* Clear prev settings */
+       data    &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07));
+       data    |= AC1_DACFS(rate_reg_info[count].divisor) |
+                       AC1_ADCFS(rate_reg_info[count].divisor);
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_1, data);
+
+       /* Set the AC3 */
+       data    = tsc2101_audio_read(TSC2101_AUDIO_CTRL_3);
+       /*Clear prev settings */
+       data    &= ~(AC3_REFFS | AC3_SLVMS);
+       data    |= (rate_reg_info[count].fs_44kHz) ? AC3_REFFS : 0;
+#ifdef TSC_MASTER
+       data    |= AC3_SLVMS;
+#endif                         /* #ifdef TSC_MASTER */
+       tsc2101_audio_write(TSC2101_AUDIO_CTRL_3, data);
+
+       /*
+        * Program the PLLs. This code assumes that the 12 Mhz MCLK is in use.
+        * If MCLK rate is something else, these values must be changed.
+        * See the tsc2101 specification for the details.
+        */
+       if (rate_reg_info[count].fs_44kHz) {
+               /* samplerate = (44.1kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                               /* PVAL 1; I_VAL 7 */
+                               PLL1_PVAL(1) | PLL1_I_VAL(7));
+               /* D_VAL 5264 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490));
+       } else {
+               /* samplerate = (48.kHZ / x), where x is int. */
+               tsc2101_audio_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL |
+                               /* PVAL 1; I_VAL 8 */
+                              PLL1_PVAL(1) | PLL1_I_VAL(8));
+               /* D_VAL 1920 */
+               tsc2101_audio_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780));
+       }
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv  = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return (1);
+
+       /* Stereo Mode */
+       srgr2 = (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1));
+#else
+       srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       srgr2 = ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)));
+
+#endif                         /* end of #ifdef TSC_MASTER */
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1610_MCBSP1_BASE, SRGR1, srgr1);
+}
+
+void tsc2101_configure(void)
+{
+}
+
+/*
+ *  Omap MCBSP clock and Power Management configuration
+ *
+ *  Here we have some functions that allows clock to be enabled and
+ *   disabled only when needed. Besides doing clock configuration
+ *   it allows turn on/turn off audio when necessary.
+ */
+
+/*
+ * Do clock framework mclk search
+ */
+void tsc2101_clock_setup(void)
+{
+       tsc2101_mclk = clk_get(0, "mclk");
+}
+
+/*
+ * Do some sanity check, set clock rate, starts it and turn codec audio on
+ */
+int tsc2101_clock_on(void)
+{
+       int     curUseCount;
+       uint    curRate;
+       int     err;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if (curUseCount > 0) {
+               /* MCLK is already in use */
+               printk(KERN_WARNING
+                      "MCLK already in use at %d Hz. We change it to %d Hz\n",
+                      (uint) clk_get_rate(tsc2101_mclk),
+                      CODEC_CLOCK);
+       }
+       curRate = (uint)clk_get_rate(tsc2101_mclk);
+       if (curRate != CODEC_CLOCK) {
+               err     = clk_set_rate(tsc2101_mclk, CODEC_CLOCK);
+               if (err) {
+                       printk(KERN_WARNING "Cannot set MCLK clock rate for "
+                               "TSC2101 CODEC, error code = %d\n", err);
+                       return -ECANCELED;
+               }
+       }
+       err             = clk_enable(tsc2101_mclk);
+       curRate         = (uint)clk_get_rate(tsc2101_mclk);
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("MCLK = %d [%d], usecount = %d, clk_enable retval = %d\n",
+              curRate,
+              CODEC_CLOCK,
+              curUseCount,
+              err);
+
+       /* Now turn the audio on */
+       tsc2101_write_sync(mcbsp_dev.tsc2101_dev, PAGE2_AUDIO_CODEC_REGISTERS,
+                               TSC2101_CODEC_POWER_CTRL,
+                               0x0000);
+       return 0;
+}
+
+/*
+ * Do some sanity check, turn clock off and then turn codec audio off
+ */
+int tsc2101_clock_off(void)
+{
+       int curUseCount;
+       int curRate;
+
+       curUseCount     = clk_get_usecount(tsc2101_mclk);
+       DPRINTK("clock use count = %d\n", curUseCount);
+       if  (curUseCount > 0) {
+               curRate = clk_get_rate(tsc2101_mclk);
+               DPRINTK("clock rate = %d\n", curRate);
+               if (curRate != CODEC_CLOCK) {
+                       printk(KERN_WARNING
+                              "MCLK for audio should be %d Hz. But is %d Hz\n",
+                              (uint) clk_get_rate(tsc2101_mclk),
+                              CODEC_CLOCK);
+               }
+               clk_disable(tsc2101_mclk);
+               DPRINTK("clock disabled\n");
+       }
+       tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
+                           ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC));
+       DPRINTK("audio codec off\n");
+       return 0;
+}
+
+int tsc2101_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int __devinit snd_omap_alsa_tsc2101_probe(struct platform_device *pdev)
+{
+       struct spi_device *tsc2101;
+       int     ret;
+       struct  omap_alsa_codec_config *codec_cfg;
+
+       tsc2101 = dev_get_drvdata(&pdev->dev);
+       if (tsc2101 == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               return -ENODEV;
+       }
+       if (strncmp(tsc2101->modalias, "tsc2101", 8) != 0) {
+               dev_err(&pdev->dev, "tsc2101 not found\n");
+               return -EINVAL;
+       }
+       mcbsp_dev.mcbsp_dev = pdev;
+       mcbsp_dev.tsc2101_dev = tsc2101;
+
+       codec_cfg = pdev->dev.platform_data;
+       if (codec_cfg != NULL) {
+               codec_cfg->hw_constraints_rates =
+                                               &tsc2101_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback =
+                                       &tsc2101_snd_omap_alsa_playback;
+               codec_cfg->snd_omap_alsa_capture =
+                                               &tsc2101_snd_omap_alsa_capture;
+               codec_cfg->codec_configure_dev  = tsc2101_configure;
+               codec_cfg->codec_set_samplerate = tsc2101_set_samplerate;
+               codec_cfg->codec_clock_setup    = tsc2101_clock_setup;
+               codec_cfg->codec_clock_on       = tsc2101_clock_on;
+               codec_cfg->codec_clock_off      = tsc2101_clock_off;
+               codec_cfg->get_default_samplerate =
+                                               tsc2101_get_default_samplerate;
+               ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       } else
+               ret = -ENODEV;
+       return ret;
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2101_probe,
+       .remove         = snd_omap_alsa_remove,
+       .suspend        = snd_omap_alsa_suspend,
+       .resume         = snd_omap_alsa_resume,
+       .driver = {
+               .name = "omap_alsa_mcbsp",
+       },
+};
+
+static int __init omap_alsa_tsc2101_init(void)
+{
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk(KERN_INFO "omap_alsa_tsc2101_init()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       return platform_driver_register(&omap_alsa_driver);
+}
+
+static void __exit omap_alsa_tsc2101_exit(void)
+{
+       ADEBUG();
+#ifdef DUMP_TSC2101_AUDIO_REGISTERS
+       printk(KERN_INFO "omap_alsa_tsc2101_exit()\n");
+       dump_tsc2101_audio_reg();
+#endif
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2101_init);
+module_exit(omap_alsa_tsc2101_exit);
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..fb03801
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2101.h
+ *
+ * Alsa Driver for TSC2101 codec for OMAP platform boards.
+ *
+ * Based on former omap-aic23.h and tsc2101 OSS drivers.
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *     Written by Nishanth Menon and Sriram Kannan
+ *
+ * Copyright (C) 2006 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ *          Alsa modularization by Daniel Petrini (d.pensator@gmail.com)
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2101_H_
+#define OMAP_ALSA_TSC2101_H_
+
+#include <linux/types.h>
+
+/* Define to set the tsc as the master w.r.t McBSP or EAC */
+#define TSC_MASTER
+
+#define NUMBER_SAMPLE_RATES_SUPPORTED  16
+
+/*
+ * AUDIO related MACROS
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+
+/* FIXME codec clock rate is board-specific */
+#define CODEC_CLOCK                    12000000
+
+#define PAGE2_AUDIO_CODEC_REGISTERS    (2)
+
+struct mcbsp_dev_info {
+       struct platform_device *mcbsp_dev;
+       struct spi_device *tsc2101_dev;
+};
+
+struct tsc2101_samplerate_reg_info {
+       u16 sample_rate;
+       u8 divisor;
+       u8 fs_44kHz;    /* if 0 48 khz, if 1 44.1 khz fsref */
+};
+
+/*
+ * Defines codec specific function pointers that can be used from the
+ * common omap-alse base driver for all omap codecs. (tsc2101 and aic23)
+ */
+inline void tsc2101_configure(void);
+void tsc2101_set_samplerate(long rate);
+void tsc2101_clock_setup(void);
+int tsc2101_clock_on(void);
+int tsc2101_clock_off(void);
+int tsc2101_get_default_samplerate(void);
+
+#endif /*OMAP_ALSA_TSC2101_H_*/
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..74c1fd6
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * 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 <mach/omap-alsa.h>
+
+#include <sound/initval.h>
+#include <sound/control.h>
+
+#include "omap-alsa-tsc2102.h"
+#include "omap-alsa-dma.h"
+
+static int vol[2], mute[2], filter[2];
+
+/*
+ * Converts the Alsa mixer volume (0 - 100) to actual Digital
+ * Gain Control (DGC) value that can be written or read from the
+ * TSC2102 registers.
+ *
+ * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
+ * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser.  (The
+ * higher the value sent to DAC, the more the volume of controlled
+ * channel is decreased)
+ */
+static void set_dac_gain_stereo(int left_ch, int right_ch)
+{
+       int lch, rch;
+
+       if (left_ch > 100)
+               vol[0] = 100;
+       else if (left_ch < 0)
+               vol[0] = 0;
+       else
+               vol[0] = left_ch;
+       lch = OUTPUT_VOLUME_MIN - vol[0] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       if (right_ch > 100)
+               vol[1] = 100;
+       else if (right_ch < 0)
+               vol[1] = 0;
+       else
+               vol[1] = right_ch;
+       rch = OUTPUT_VOLUME_MIN - vol[1] *
+               (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
+
+       tsc2102_set_volume(lch, rch);
+}
+
+void init_playback_targets(void)
+{
+       set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
+
+       /* Unmute */
+       tsc2102_set_mute(0, 0);
+
+       mute[0] = 0;
+       mute[1] = 0;
+       filter[0] = 0;
+       filter[1] = 0;
+}
+
+/*
+ * Initializes TSC 2102 and playback target.
+ */
+void snd_omap_init_mixer(void)
+{
+       FN_IN;
+
+       init_playback_targets();
+
+       FN_OUT(0);
+}
+
+static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 100;
+       return 0;
+}
+
+static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = vol[0];      /* L */
+       ucontrol->value.integer.value[1] = vol[1];      /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       set_dac_gain_stereo(
+                       ucontrol->value.integer.value[0],       /* L */
+                       ucontrol->value.integer.value[1]);      /* R */
+       return 1;
+}
+
+static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 2;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = !mute[0];            /* L */
+       ucontrol->value.integer.value[1] = !mute[1];            /* R */
+
+       return 0;
+}
+
+static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       mute[0] = (ucontrol->value.integer.value[0] == 0);      /* L */
+       mute[1] = (ucontrol->value.integer.value[1] == 0);      /* R */
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       return 1;
+}
+
+static int __pcm_playback_deemphasis_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[0];
+       return 0;
+}
+
+static int __pcm_playback_deemphasis_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       filter[0] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_deemphasis(filter[0]);
+       return 1;
+}
+
+static int __pcm_playback_bassboost_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count                    = 1;
+       uinfo->value.integer.min        = 0;
+       uinfo->value.integer.max        = 1;
+       return 0;
+}
+
+static int __pcm_playback_bassboost_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = filter[1];
+       return 0;
+}
+
+static int __pcm_playback_bassboost_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       filter[1] = (ucontrol->value.integer.value[0] > 0);
+
+       tsc2102_set_bassboost(filter[1]);
+       return 1;
+}
+
+static struct snd_kcontrol_new tsc2102_controls[] __devinitdata = {
+       {
+               .name   = "Master Playback Volume",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_volume_info,
+               .get    = __pcm_playback_volume_get,
+               .put    = __pcm_playback_volume_put,
+       },
+       {
+               .name   = "Master Playback Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_switch_info,
+               .get    = __pcm_playback_switch_get,
+               .put    = __pcm_playback_switch_put,
+       },
+       {
+               .name   = "De-emphasis Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_deemphasis_info,
+               .get    = __pcm_playback_deemphasis_get,
+               .put    = __pcm_playback_deemphasis_put,
+       },
+       {
+               .name   = "Bass-boost Filter Switch",
+               .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .index  = 0,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info   = __pcm_playback_bassboost_info,
+               .get    = __pcm_playback_bassboost_get,
+               .put    = __pcm_playback_bassboost_put,
+       },
+};
+
+#ifdef CONFIG_PM
+void snd_omap_suspend_mixer(void)
+{
+       /* Nothing to do */
+}
+
+void snd_omap_resume_mixer(void)
+{
+       /* The chip was reset, restore the last used values */
+       set_dac_gain_stereo(vol[0], vol[1]);
+
+       tsc2102_set_mute(mute[0], mute[1]);
+       tsc2102_set_deemphasis(filter[0]);
+       tsc2102_set_bassboost(filter[1]);
+}
+#endif
+
+int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
+{
+       int i, err;
+
+       if (!tsc2102)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(tsc2102_controls); i++) {
+               err = snd_ctl_add(tsc2102->card,
+                               snd_ctl_new1(&tsc2102_controls[i],
+                               tsc2102->card));
+
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
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..4c34f7c
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.c
+ *
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/spi/tsc2102.h>
+
+#include <mach/dma.h>
+#include <mach/clock.h>
+#include <mach/omap-alsa.h>
+
+#include "omap-alsa-tsc2102.h"
+
+static struct clk *tsc2102_bclk;
+
+/*
+ * Hardware capabilities
+ */
+
+/* DAC sampling rates (BCLK = 12 MHz) */
+static unsigned int rates[] = {
+       7350, 8000, 8820, 9600, 11025, 12000, 14700,
+       16000, 22050, 24000, 29400, 32000, 44100, 48000,
+};
+
+static struct snd_pcm_hw_constraint_list tsc2102_hw_constraints_rates = {
+       .count = ARRAY_SIZE(rates),
+       .list = rates,
+       .mask = 0,
+};
+
+static struct snd_pcm_hardware tsc2102_snd_omap_alsa_playback = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID,
+       .formats                = SNDRV_PCM_FMTBIT_S16_LE,
+       .rates                  = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
+               SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_KNOT,
+       .rate_min               = 7350,
+       .rate_max               = 48000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 128 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8 * 1024,
+       .periods_min            = 16,
+       .periods_max            = 255,
+       .fifo_size              = 0,
+};
+
+#ifdef DUMP_TSC2102_AUDIO_REGISTERS
+static void dump_tsc2102_audio_regs(void)
+{
+       printk(KERN_INFO "TSC2102_AUDIO1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO1_CTRL));
+       printk(KERN_INFO "TSC2102_DAC_GAIN_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_GAIN_CTRL));
+       printk(KERN_INFO "TSC2102_AUDIO2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO2_CTRL));
+       printk(KERN_INFO "TSC2102_DAC_POWER_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_DAC_POWER_CTRL));
+       printk(KERN_INFO "TSC2102_AUDIO3_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO_CTRL_3));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N0));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N1));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N2));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N3));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N4));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_N5));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D1));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D2));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D4));
+       printk(KERN_INFO "TSC2102_LCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_LCH_BASS_BOOST_D5));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N0 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N0));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N1));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N2));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N3 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N3));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N4));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_N5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_N5));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D1 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D1));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D2 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D2));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D4 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D4));
+       printk(KERN_INFO "TSC2102_RCH_BASS_BOOST_D5 = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_RCH_BASS_BOOST_D5));
+       printk(KERN_INFO "TSC2102_PLL1_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL1_CTRL));
+       printk(KERN_INFO "TSC2102_PLL2_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_PLL2_CTRL));
+       printk(KERN_INFO "TSC2102_AUDIO4_CTRL = 0x%04x\n",
+                       tsc2102_read_sync(TSC2102_AUDIO4_CTRL));
+}
+#endif
+
+/*
+ * ALSA operations according to board file
+ */
+
+static long current_rate;
+
+/*
+ * Sample rate changing
+ */
+static void tsc2102_set_samplerate(long sample_rate)
+{
+       int clkgdv = 0;
+       u16 srgr1, srgr2;
+
+       if (sample_rate == current_rate)
+               return;
+       current_rate = 0;
+
+       if (tsc2102_set_rate(sample_rate))
+               return;
+
+       /* Set the sample rate */
+#ifndef TSC_MASTER
+       clkgdv = CODEC_CLOCK / (sample_rate * (DEFAULT_BITPERSAMPLE * 2 - 1));
+       if (clkgdv)
+               srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv));
+       else
+               return;
+
+       /* Stereo Mode */
+       srgr2 = CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#else
+       srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv);
+       srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1);
+#endif
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR2, srgr2);
+       OMAP_MCBSP_WRITE(OMAP1510_MCBSP1_BASE, SRGR1, srgr1);
+       current_rate = sample_rate;
+}
+
+static void tsc2102_configure(void)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+}
+
+/*
+ * Omap McBSP clock and Power Management configuration
+ *
+ * Here we have some functions that allow clock to be enabled and
+ * disabled only when needed.  Besides doing clock configuration
+ * they allow turn audio on and off when necessary.
+ */
+
+/*
+ * Do clock framework bclk search
+ */
+static void tsc2102_clock_setup(void)
+{
+       tsc2102_bclk = clk_get(0, "bclk");
+}
+
+/*
+ * Do some sanity checks, set clock rate, start it.
+ */
+static int tsc2102_clock_on(void)
+{
+       int err;
+
+       if (clk_get_usecount(tsc2102_bclk) > 0 &&
+                       clk_get_rate(tsc2102_bclk) != CODEC_CLOCK) {
+               /* BCLK is already in use */
+               printk(KERN_WARNING
+                       "BCLK already in use at %d Hz. We change it to %d Hz\n",
+                       (uint) clk_get_rate(tsc2102_bclk), CODEC_CLOCK);
+
+               err = clk_set_rate(tsc2102_bclk, CODEC_CLOCK);
+               if (err)
+                       printk(KERN_WARNING "Cannot set BCLK clock rate "
+                               "for TSC2102 codec, error code = %d\n", err);
+       }
+
+       clk_enable(tsc2102_bclk);
+       return 0;
+}
+
+/*
+ * Turn off the audio codec and then stop the clock.
+ */
+static int tsc2102_clock_off(void)
+{
+       DPRINTK("clock use count = %d\n", clk_get_usecount(tsc2102_bclk));
+
+       clk_disable(tsc2102_bclk);
+       return 0;
+}
+
+static int tsc2102_get_default_samplerate(void)
+{
+       return DEFAULT_SAMPLE_RATE;
+}
+
+static int snd_omap_alsa_tsc2102_suspend(
+               struct platform_device *pdev, pm_message_t state)
+{
+       tsc2102_dac_power(0);
+       current_rate = 0;
+
+       return snd_omap_alsa_suspend(pdev, state);
+}
+
+static int snd_omap_alsa_tsc2102_resume(struct platform_device *pdev)
+{
+       tsc2102_dac_power(1);
+
+#ifdef TSC_MASTER
+       tsc2102_set_i2s_master(1);
+#else
+       tsc2102_set_i2s_master(0);
+#endif
+
+       return snd_omap_alsa_resume(pdev);
+}
+
+static int __init snd_omap_alsa_tsc2102_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct omap_alsa_codec_config *codec_cfg = pdev->dev.platform_data;
+
+       if (codec_cfg) {
+               codec_cfg->hw_constraints_rates =
+                       &tsc2102_hw_constraints_rates;
+               codec_cfg->snd_omap_alsa_playback =
+                       &tsc2102_snd_omap_alsa_playback;
+               codec_cfg->codec_configure_dev = tsc2102_configure;
+               codec_cfg->codec_set_samplerate = tsc2102_set_samplerate;
+               codec_cfg->codec_clock_setup = tsc2102_clock_setup;
+               codec_cfg->codec_clock_on = tsc2102_clock_on;
+               codec_cfg->codec_clock_off = tsc2102_clock_off;
+               codec_cfg->get_default_samplerate =
+                       tsc2102_get_default_samplerate;
+               ret = snd_omap_alsa_post_probe(pdev, codec_cfg);
+       } else
+               ret = -ENODEV;
+
+       return ret;
+}
+
+static int snd_omap_alsa_tsc2102_remove(struct platform_device *pdev)
+{
+       tsc2102_dac_power(0);
+
+       return snd_omap_alsa_remove(pdev);
+}
+
+static struct platform_driver omap_alsa_driver = {
+       .probe          = snd_omap_alsa_tsc2102_probe,
+       .remove         = snd_omap_alsa_tsc2102_remove,
+       .suspend        = snd_omap_alsa_tsc2102_suspend,
+       .resume         = snd_omap_alsa_tsc2102_resume,
+       .driver         = {
+               .name   = "tsc2102-alsa",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init omap_alsa_tsc2102_init(void)
+{
+       int err;
+
+       ADEBUG();
+       err = platform_driver_register(&omap_alsa_driver);
+
+       return err;
+}
+
+static void __exit omap_alsa_tsc2102_exit(void)
+{
+       ADEBUG();
+       platform_driver_unregister(&omap_alsa_driver);
+}
+
+module_init(omap_alsa_tsc2102_init);
+module_exit(omap_alsa_tsc2102_exit);
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..0e0c097
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * sound/arm/omap/omap-alsa-tsc2102.h
+ *
+ * Alsa codec driver for TSC2102 chip for OMAP platforms.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Code based on the TSC2101 ALSA driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef OMAP_ALSA_TSC2102_H_
+#define OMAP_ALSA_TSC2102_H_
+
+/* Define to set the tsc as the master w.r.t McBSP */
+#define TSC_MASTER
+
+/*
+ * Audio related macros
+ */
+#ifndef DEFAULT_BITPERSAMPLE
+#define DEFAULT_BITPERSAMPLE           16
+#endif
+
+#define DEFAULT_SAMPLE_RATE            44100
+
+/* FIXME codec clock rate is board-specific */
+#define CODEC_CLOCK                    12000000
+
+/*
+ * ALSA mixer related macros
+ */
+#define OUTPUT_VOLUME_MIN              0x7f    /* 1111111 = -63.5 dB */
+#define OUTPUT_VOLUME_MAX              0x00    /* 0000000 */
+#define OUTPUT_VOLUME_RANGE            (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX)
+
+#define DEFAULT_OUTPUT_VOLUME          90      /* Default output volume */
+
+#endif /* OMAP_ALSA_TSC2102_H_ */
diff --git a/sound/arm/omap/omap-alsa.c b/sound/arm/omap/omap-alsa.c
new file mode 100644 (file)
index 0000000..45c46e2
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * sound/arm/omap-alsa.c
+ *
+ * Alsa Driver for OMAP
+ *
+ * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
+ * Written by Daniel Petrini, David Cohen, Anderson Briglia
+ *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
+ *
+ * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
+ *
+ * Based on sa11xx-uda1341.c,
+ * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ * 2005-07-29   INdT Kernel Team - Alsa driver for omap osk. Creation of new
+ *                                 file omap-aic23.c
+ *
+ * 2005-12-18   Dirk Behme       - Added L/R Channel Interchange fix as proposed
+ *                                 by Ajaya Babu
+ *
+ */
+
+#include <linux/platform_device.h>
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include <mach/omap-alsa.h>
+#include "omap-alsa-dma.h"
+
+MODULE_AUTHOR("Mika Laitio");
+MODULE_AUTHOR("Daniel Petrini");
+MODULE_AUTHOR("David Cohen");
+MODULE_AUTHOR("Anderson Briglia");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OMAP driver for ALSA");
+MODULE_ALIAS("omap_alsa_mcbsp.1");
+
+static char *id;
+static struct snd_card_omap_codec      *alsa_codec;
+static struct omap_alsa_codec_config   *alsa_codec_config;
+
+/* FIXME: Please change to use omap asoc framework instead, this can be racy */
+static dma_addr_t dma_start_pos;
+
+/*
+ * HW interface start and stop helper functions
+ */
+static int audio_ifc_start(void)
+{
+       omap_mcbsp_start(AUDIO_MCBSP);
+       return 0;
+}
+
+static int audio_ifc_stop(void)
+{
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       return 0;
+}
+
+static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
+{
+       /* Setup DMA stuff */
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
+           SNDRV_PCM_STREAM_PLAYBACK;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
+           OMAP_DMA_MCBSP1_TX;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
+           audio_ifc_stop;
+
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
+           SNDRV_PCM_STREAM_CAPTURE;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
+           OMAP_DMA_MCBSP1_RX;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
+           audio_ifc_start;
+       omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
+           audio_ifc_stop;
+}
+
+/*
+ * DMA functions
+ * Depends on omap-alsa-dma.c functions and (omap) dma.c
+ */
+static int audio_dma_request(struct audio_stream *s,
+                            void (*callback) (void *))
+{
+       int err;
+       ADEBUG();
+
+       err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
+       return err;
+}
+
+static int audio_dma_free(struct audio_stream *s)
+{
+       int err = 0;
+       ADEBUG();
+
+       err = omap_free_alsa_sound_dma(s, &s->lch);
+       if (err < 0)
+               printk(KERN_ERR "Unable to free audio dma channels!\n");
+       return err;
+}
+
+/*
+ *  This function should calculate the current position of the dma in the
+ *  buffer. It will help alsa middle layer to continue update the buffer.
+ *  Its correctness is crucial for good functioning.
+ */
+static u_int audio_get_dma_pos(struct audio_stream *s)
+{
+       struct snd_pcm_substream *substream = s->stream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       unsigned int offset;
+       unsigned long flags;
+       dma_addr_t count;
+       ADEBUG();
+
+       /* this must be called w/ interrupts locked as requested in dma.c */
+       spin_lock_irqsave(&s->dma_lock, flags);
+
+       /* For the current period let's see where we are */
+       count = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - dma_start_pos;
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+
+       /* Now, the position related to the end of that period */
+       offset = bytes_to_frames(runtime, s->offset) -
+                       bytes_to_frames(runtime, count);
+
+       if (offset >= runtime->buffer_size)
+               offset = 0;
+
+       return offset;
+}
+
+/*
+ * this stops the dma and clears the dma ptrs
+ */
+static void audio_stop_dma(struct audio_stream *s)
+{
+       unsigned long flags;
+       ADEBUG();
+
+       spin_lock_irqsave(&s->dma_lock, flags);
+       s->active = 0;
+       s->period = 0;
+       s->periods = 0;
+
+       /* this stops the dma channel and clears the buffer ptrs */
+       omap_stop_alsa_sound_dma(s);
+
+       omap_clear_alsa_sound_dma(s);
+
+       spin_unlock_irqrestore(&s->dma_lock, flags);
+}
+
+/*
+ *  Main dma routine, requests dma according where you are in main alsa buffer
+ */
+static void audio_process_dma(struct audio_stream *s)
+{
+       struct snd_pcm_substream *substream = s->stream;
+       struct snd_pcm_runtime *runtime;
+       unsigned int dma_size;
+       unsigned int offset;
+       int ret;
+
+       ADEBUG();
+       runtime = substream->runtime;
+       if (s->active) {
+               dma_size = frames_to_bytes(runtime, runtime->period_size);
+               offset = dma_size * s->period;
+               snd_assert(dma_size <= DMA_BUF_SIZE, return);
+               /*
+                * On omap1510 based devices, we need to call the stop_dma
+                * before calling the start_dma or we will not receive the
+                * irq from DMA after the first transfered/played buffer.
+                * (invocation of callback_omap_alsa_sound_dma() method).
+                */
+               if (cpu_is_omap1510())
+                       omap_stop_alsa_sound_dma(s);
+
+               dma_start_pos = (dma_addr_t)runtime->dma_area + offset;
+               ret = omap_start_alsa_sound_dma(s, dma_start_pos, dma_size);
+               if (ret) {
+                       printk(KERN_ERR "audio_process_dma: cannot"
+                                       " queue DMA buffer (%i)\n", ret);
+                       return;
+               }
+
+               s->period++;
+               s->period %= runtime->periods;
+               s->periods++;
+               s->offset = offset;
+       }
+}
+
+/*
+ *  This is called when dma IRQ occurs at the end of each transmited block
+ */
+void callback_omap_alsa_sound_dma(void *data)
+{
+       struct audio_stream *s = data;
+
+       ADEBUG();
+       /*
+        * If we are getting a callback for an active stream then we inform
+        * the PCM middle layer we've finished a period
+        */
+       if (s->active)
+               snd_pcm_period_elapsed(s->stream);
+
+       spin_lock(&s->dma_lock);
+       if (s->periods > 0)
+               s->periods--;
+
+       audio_process_dma(s);
+       spin_unlock(&s->dma_lock);
+}
+
+/*
+ * Alsa section
+ * PCM settings and callbacks
+ */
+static int snd_omap_alsa_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       int stream_id = substream->pstr->stream;
+       struct audio_stream *s = &chip->s[stream_id];
+       int err = 0;
+
+       ADEBUG();
+       /* note local interrupts are already disabled in the midlevel code */
+       spin_lock(&s->dma_lock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* requested stream startup */
+               s->active = 1;
+               audio_process_dma(s);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               /* requested stream shutdown */
+               audio_stop_dma(s);
+               break;
+       default:
+               err = -EINVAL;
+               break;
+       }
+       spin_unlock(&s->dma_lock);
+
+       return err;
+}
+
+static int snd_omap_alsa_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct audio_stream *s = &chip->s[substream->pstr->stream];
+
+       ADEBUG();
+       /* set requested samplerate */
+       alsa_codec_config->codec_set_samplerate(runtime->rate);
+       chip->samplerate = runtime->rate;
+
+       s->period = 0;
+       s->periods = 0;
+
+       return 0;
+}
+
+static snd_pcm_uframes_t
+snd_omap_alsa_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+       ADEBUG();
+       return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
+}
+
+static int snd_card_omap_alsa_open(struct snd_pcm_substream *substream)
+{
+       struct snd_card_omap_codec *chip =
+           snd_pcm_substream_chip(substream);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int stream_id = substream->pstr->stream;
+       int err;
+
+       ADEBUG();
+       chip->s[stream_id].stream = substream;
+       alsa_codec_config->codec_clock_on();
+       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
+       else
+               runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
+
+       err = snd_pcm_hw_constraint_integer(runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIODS);
+       if (err < 0)
+               return err;
+
+       err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                               alsa_codec_config->hw_constraints_rates);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int snd_card_omap_alsa_close(struct snd_pcm_substream *substream)
+{
+       struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
+
+       ADEBUG();
+       alsa_codec_config->codec_clock_off();
+       chip->s[substream->pstr->stream].stream = NULL;
+
+       return 0;
+}
+
+/* HW params & free */
+static int snd_omap_alsa_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static int snd_omap_alsa_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* pcm operations */
+static struct snd_pcm_ops snd_card_omap_alsa_playback_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+static struct snd_pcm_ops snd_card_omap_alsa_capture_ops = {
+       .open =         snd_card_omap_alsa_open,
+       .close =        snd_card_omap_alsa_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    snd_omap_alsa_hw_params,
+       .hw_free =      snd_omap_alsa_hw_free,
+       .prepare =      snd_omap_alsa_prepare,
+       .trigger =      snd_omap_alsa_trigger,
+       .pointer =      snd_omap_alsa_pointer,
+};
+
+/*
+ *  Alsa init and exit section
+ *  Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
+ */
+static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa,
+                                       int device)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       ADEBUG();
+       err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm);
+       if (err < 0)
+               return err;
+
+       /* sets up initial buffer with continuous allocation */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                             SNDRV_DMA_TYPE_CONTINUOUS,
+                                             snd_dma_continuous_data
+                                             (GFP_KERNEL),
+                                             128 * 1024, 128 * 1024);
+
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_card_omap_alsa_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &snd_card_omap_alsa_capture_ops);
+       pcm->private_data = omap_alsa;
+       pcm->info_flags = 0;
+       strcpy(pcm->name, "omap alsa pcm");
+
+       omap_alsa_audio_init(omap_alsa);
+
+       /* setup DMA controller */
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
+                         callback_omap_alsa_sound_dma);
+       audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
+                         callback_omap_alsa_sound_dma);
+
+       omap_alsa->pcm = pcm;
+
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+/*
+ * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
+ */
+int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_card_omap_codec *chip;
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       if (card->power_state != SNDRV_CTL_POWER_D3hot) {
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
+                       snd_power_change_state(chip->card,
+                                               SNDRV_CTL_POWER_D3hot);
+                       snd_pcm_suspend_all(chip->pcm);
+                       /* Mutes and turn clock off */
+                       alsa_codec_config->codec_clock_off();
+                       snd_omap_suspend_mixer();
+               }
+       }
+       return 0;
+}
+
+int snd_omap_alsa_resume(struct platform_device *pdev)
+{
+       struct snd_card_omap_codec *chip;
+       struct snd_card *card = platform_get_drvdata(pdev);
+
+       if (card->power_state != SNDRV_CTL_POWER_D0) {
+               chip = card->private_data;
+               if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
+                       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+                       alsa_codec_config->codec_clock_on();
+                       snd_omap_resume_mixer();
+               }
+       }
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+void snd_omap_alsa_free(struct snd_card *card)
+{
+       struct snd_card_omap_codec *chip = card->private_data;
+       ADEBUG();
+
+       /*
+        * Turn off codec after it is done.
+        * Can't do it immediately, since it may still have
+        * buffered data.
+        */
+       schedule_timeout_interruptible(2);
+
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
+       audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
+}
+
+/* module init & exit */
+
+/*
+ * Inits alsa soudcard structure.
+ * Called by the probe method in codec after function pointers has been set.
+ */
+int snd_omap_alsa_post_probe(struct platform_device *pdev,
+                               struct omap_alsa_codec_config *config)
+{
+       int err = 0;
+       int def_rate;
+       struct snd_card *card;
+
+       ADEBUG();
+       alsa_codec_config       = config;
+
+       alsa_codec_config->codec_clock_setup();
+       alsa_codec_config->codec_clock_on();
+
+       omap_mcbsp_request(AUDIO_MCBSP);
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
+       omap_mcbsp_start(AUDIO_MCBSP);
+
+       if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
+               alsa_codec_config->codec_configure_dev();
+
+       alsa_codec_config->codec_clock_off();
+
+       /* register the soundcard */
+       card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
+       if (card == NULL)
+               goto nodev1;
+
+       alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
+       if (alsa_codec == NULL)
+               goto nodev2;
+
+       card->private_data = (void *)alsa_codec;
+       card->private_free = snd_omap_alsa_free;
+
+       alsa_codec->card        = card;
+       def_rate                = alsa_codec_config->get_default_samplerate();
+       alsa_codec->samplerate  = def_rate;
+
+       spin_lock_init(&alsa_codec->s[0].dma_lock);
+       spin_lock_init(&alsa_codec->s[1].dma_lock);
+
+       /* mixer */
+       err = snd_omap_mixer(alsa_codec);
+       if (err < 0)
+               goto nodev3;
+
+       /* PCM */
+       err = snd_card_omap_alsa_pcm(alsa_codec, 0);
+       if (err < 0)
+               goto nodev3;
+
+       strcpy(card->driver, "OMAP_ALSA");
+       strcpy(card->shortname, alsa_codec_config->name);
+       sprintf(card->longname, alsa_codec_config->name);
+
+       snd_omap_init_mixer();
+       snd_card_set_dev(card, &pdev->dev);
+
+       err = snd_card_register(card);
+       if (err == 0) {
+               printk(KERN_INFO "audio support initialized\n");
+               platform_set_drvdata(pdev, card);
+               return 0;
+       }
+
+nodev3:
+       kfree(alsa_codec);
+nodev2:
+       snd_card_free(card);
+nodev1:
+       omap_mcbsp_stop(AUDIO_MCBSP);
+       omap_mcbsp_free(AUDIO_MCBSP);
+
+       return err;
+}
+
+int snd_omap_alsa_remove(struct platform_device *pdev)
+{
+       struct snd_card *card = platform_get_drvdata(pdev);
+       struct snd_card_omap_codec *chip = card->private_data;
+
+       snd_card_free(card);
+
+       alsa_codec = NULL;
+       card->private_data = NULL;
+       kfree(chip);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
index c611514f7ff104ec3289d960d9108d5391fc91c9..45b56473b4fbef30fca3e1296f9fba1ee914e13c 100644 (file)
@@ -7,6 +7,10 @@
 
 obj-$(CONFIG_SOUND_OSS)                += sound.o
 
+obj-$(CONFIG_SOUND_OMAP)        += omap-audio-dma-intfc.o omap-audio.o
+obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o
+obj-$(CONFIG_SOUND_OMAP_AIC23)  += omap-audio-aic23.o
+
 # Please leave it as is, cause the link order is significant !
 
 obj-$(CONFIG_SOUND_SH_DAC_AUDIO)       += sh_dac_audio.o
diff --git a/sound/oss/omap-audio-aic23.c b/sound/oss/omap-audio-aic23.c
new file mode 100644 (file)
index 0000000..c603aaa
--- /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 <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/mcbsp.h>
+#include <mach/fpga.h>
+#include <mach/aic23.h>
+#include <mach/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..c6a6136
--- /dev/null
@@ -0,0 +1,985 @@
+/*
+ * 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 <mach/hardware.h>
+#include <asm/semaphore.h>
+
+#include <mach/dma.h>
+#include "omap-audio-dma-intfc.h"
+
+#include <mach/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_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_stop_dma(sound_curr_lch);
+               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..4931ecf
--- /dev/null
@@ -0,0 +1,1237 @@
+/*
+ * 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 <mach/hardware.h>
+#include <mach/dma.h>
+#include <asm/io.h>
+
+#include <mach/mux.h>
+#include <mach/io.h>
+#include <asm/mach-types.h>
+
+#include "omap-audio.h"
+#include "omap-audio-dma-intfc.h"
+#include <mach/mcbsp.h>
+#ifdef CONFIG_ARCH_OMAP16XX
+#include <../drivers/ssi/omap-uwire.h>
+#include <mach/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..95b5eef
--- /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 <mach/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..895d803
--- /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 <mach/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 */
index 1db04a28a53d46c7732401a2375ea904db158af6..b1a5eedbfe31bbf4e8a1344d747a112b9c2f01d6 100644 (file)
@@ -50,3 +50,8 @@ config SND_SOC_CS4270_VD33_ERRATA
 config SND_SOC_TLV320AIC3X
        tristate
        depends on I2C
+
+config SND_SOC_TWL4030
+       tristate
+       depends on SND_SOC && TWL4030_CORE
+
index d7b97abcf7291cea11e2ea29a3c687551f241b4f..a519ceda2fb7271cc0b23dc63f58cf4dd18f1918 100644 (file)
@@ -10,6 +10,7 @@ snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-cs4270-objs := cs4270.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
+snd-soc-twl4030-objs := twl4030.o
 
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_SND_SOC_WM9712)  += snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_CS4270)   += snd-soc-cs4270.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
+obj-$(CONFIG_SND_SOC_TWL4030)  += snd-soc-twl4030.o
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
new file mode 100644 (file)
index 0000000..ee2f0d3
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * ALSA SoC TWL4030 codec driver
+ *
+ * Author:      Steve Sakoman, <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "twl4030.h"
+
+/*
+ * twl4030 register cache & default register settings
+ */
+static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
+       0x00, /* this register not used         */
+       0x93, /* REG_CODEC_MODE         (0x1)   */
+       0xc3, /* REG_OPTION             (0x2)   */
+       0x00, /* REG_UNKNOWN            (0x3)   */
+       0x00, /* REG_MICBIAS_CTL        (0x4)   */
+       0x24, /* REG_ANAMICL            (0x5)   */
+       0x04, /* REG_ANAMICR            (0x6)   */
+       0x0a, /* REG_AVADC_CTL          (0x7)   */
+       0x00, /* REG_ADCMICSEL          (0x8)   */
+       0x00, /* REG_DIGMIXING          (0x9)   */
+       0x0c, /* REG_ATXL1PGA           (0xA)   */
+       0x0c, /* REG_ATXR1PGA           (0xB)   */
+       0x00, /* REG_AVTXL2PGA          (0xC)   */
+       0x00, /* REG_AVTXR2PGA          (0xD)   */
+       0x01, /* REG_AUDIO_IF           (0xE)   */
+       0x00, /* REG_VOICE_IF           (0xF)   */
+       0x00, /* REG_ARXR1PGA           (0x10)  */
+       0x00, /* REG_ARXL1PGA           (0x11)  */
+       0x6c, /* REG_ARXR2PGA           (0x12)  */
+       0x6c, /* REG_ARXL2PGA           (0x13)  */
+       0x00, /* REG_VRXPGA             (0x14)  */
+       0x00, /* REG_VSTPGA             (0x15)  */
+       0x00, /* REG_VRX2ARXPGA         (0x16)  */
+       0x0c, /* REG_AVDAC_CTL          (0x17)  */
+       0x00, /* REG_ARX2VTXPGA         (0x18)  */
+       0x00, /* REG_ARXL1_APGA_CTL     (0x19)  */
+       0x00, /* REG_ARXR1_APGA_CTL     (0x1A)  */
+       0x4b, /* REG_ARXL2_APGA_CTL     (0x1B)  */
+       0x4b, /* REG_ARXR2_APGA_CTL     (0x1C)  */
+       0x00, /* REG_ATX2ARXPGA         (0x1D)  */
+       0x00, /* REG_BT_IF              (0x1E)  */
+       0x00, /* REG_BTPGA              (0x1F)  */
+       0x00, /* REG_BTSTPGA            (0x20)  */
+       0x00, /* REG_EAR_CTL            (0x21)  */
+       0x24, /* REG_HS_SEL             (0x22)  */
+       0x0a, /* REG_HS_GAIN_SET        (0x23)  */
+       0x00, /* REG_HS_POPN_SET        (0x24)  */
+       0x00, /* REG_PREDL_CTL          (0x25)  */
+       0x00, /* REG_PREDR_CTL          (0x26)  */
+       0x00, /* REG_PRECKL_CTL         (0x27)  */
+       0x00, /* REG_PRECKR_CTL         (0x28)  */
+       0x00, /* REG_HFL_CTL            (0x29)  */
+       0x00, /* REG_HFR_CTL            (0x2A)  */
+       0x00, /* REG_ALC_CTL            (0x2B)  */
+       0x00, /* REG_ALC_SET1           (0x2C)  */
+       0x00, /* REG_ALC_SET2           (0x2D)  */
+       0x00, /* REG_BOOST_CTL          (0x2E)  */
+       0x01, /* REG_SOFTVOL_CTL        (0x2F)  */
+       0x00, /* REG_DTMF_FREQSEL       (0x30)  */
+       0x00, /* REG_DTMF_TONEXT1H      (0x31)  */
+       0x00, /* REG_DTMF_TONEXT1L      (0x32)  */
+       0x00, /* REG_DTMF_TONEXT2H      (0x33)  */
+       0x00, /* REG_DTMF_TONEXT2L      (0x34)  */
+       0x00, /* REG_DTMF_TONOFF        (0x35)  */
+       0x00, /* REG_DTMF_WANONOFF      (0x36)  */
+       0x00, /* REG_I2S_RX_SCRAMBLE_H  (0x37)  */
+       0x00, /* REG_I2S_RX_SCRAMBLE_M  (0x38)  */
+       0x00, /* REG_I2S_RX_SCRAMBLE_L  (0x39)  */
+       0x16, /* REG_APLL_CTL           (0x3A)  */
+       0x00, /* REG_DTMF_CTL           (0x3B)  */
+       0x00, /* REG_DTMF_PGA_CTL2      (0x3C)  */
+       0x00, /* REG_DTMF_PGA_CTL1      (0x3D)  */
+       0x00, /* REG_MISC_SET_1         (0x3E)  */
+       0x00, /* REG_PCMBTMUX           (0x3F)  */
+       0x00, /* not used               (0x40)  */
+       0x00, /* not used               (0x41)  */
+       0x00, /* not used               (0x42)  */
+       0x00, /* REG_RX_PATH_SEL        (0x43)  */
+       0x00, /* REG_VDL_APGA_CTL       (0x44)  */
+       0x00, /* REG_VIBRA_CTL          (0x45)  */
+       0x00, /* REG_VIBRA_SET          (0x46)  */
+       0x00, /* REG_VIBRA_PWM_SET      (0x47)  */
+       0x00, /* REG_ANAMIC_GAIN        (0x48)  */
+       0x00, /* REG_MISC_SET_2         (0x49)  */
+};
+
+/*
+ * read twl4030 register cache
+ */
+static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u8 *cache = codec->reg_cache;
+
+       return cache[reg];
+}
+
+/*
+ * write twl4030 register cache
+ */
+static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
+                                               u8 reg, u8 value)
+{
+       u8 *cache = codec->reg_cache;
+
+       if (reg >= TWL4030_CACHEREGNUM)
+               return;
+       cache[reg] = value;
+}
+
+/*
+ * write to the twl4030 register space
+ */
+static int twl4030_write(struct snd_soc_codec *codec,
+                       unsigned int reg, unsigned int value)
+{
+       twl4030_write_reg_cache(codec, reg, value);
+       return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+}
+
+static void twl4030_clear_codecpdz(struct snd_soc_codec *codec)
+{
+       u8 mode;
+
+       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+       twl4030_write(codec, TWL4030_REG_CODEC_MODE,
+               mode & ~TWL4030_CODECPDZ);
+
+       /* REVISIT: this delay is present in TI sample drivers */
+       /* but there seems to be no TRM requirement for it     */
+       udelay(10);
+}
+
+static void twl4030_set_codecpdz(struct snd_soc_codec *codec)
+{
+       u8 mode;
+
+       mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+       twl4030_write(codec, TWL4030_REG_CODEC_MODE,
+               mode | TWL4030_CODECPDZ);
+
+       /* REVISIT: this delay is present in TI sample drivers */
+       /* but there seems to be no TRM requirement for it     */
+       udelay(10);
+}
+
+static void twl4030_init_chip(struct snd_soc_codec *codec)
+{
+       int i;
+
+       /* clear CODECPDZ prior to setting register defaults */
+       twl4030_clear_codecpdz(codec);
+
+       /* set all audio section registers to reasonable defaults */
+       for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
+               twl4030_write(codec, i, twl4030_reg[i]);
+
+}
+
+static const struct snd_kcontrol_new twl4030_snd_controls[] = {
+       SOC_DOUBLE_R("Master Playback Volume",
+                TWL4030_REG_ARXL2PGA, TWL4030_REG_ARXR2PGA,
+               0, 127, 0),
+       SOC_DOUBLE_R("Capture Volume",
+                TWL4030_REG_ATXL1PGA, TWL4030_REG_ATXR1PGA,
+               0, 127, 0),
+};
+
+/* add non dapm controls */
+static int twl4030_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                                 snd_soc_cnew(&twl4030_snd_controls[i],
+                                               codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("INL"),
+       SND_SOC_DAPM_INPUT("INR"),
+
+       SND_SOC_DAPM_OUTPUT("OUTL"),
+       SND_SOC_DAPM_OUTPUT("OUTR"),
+
+       SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0),
+
+       SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       /* outputs */
+       {"OUTL", NULL, "DACL"},
+       {"OUTR", NULL, "DACR"},
+
+       /* inputs */
+       {"ADCL", NULL, "INL"},
+       {"ADCR", NULL, "INR"},
+};
+
+static int twl4030_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets,
+                                ARRAY_SIZE(twl4030_dapm_widgets));
+
+       snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
+
+       snd_soc_dapm_new_widgets(codec);
+       return 0;
+}
+
+static void twl4030_power_up(struct snd_soc_codec *codec)
+{
+       u8 anamicl, regmisc1, byte, popn, hsgain;
+       int i = 0;
+
+       /* set CODECPDZ to turn on codec */
+       twl4030_set_codecpdz(codec);
+
+       /* initiate offset cancellation */
+       anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+       twl4030_write(codec, TWL4030_REG_ANAMICL,
+               anamicl | TWL4030_CNCL_OFFSET_START);
+
+       /* wait for offset cancellation to complete */
+       do {
+               /* this takes a little while, so don't slam i2c */
+               udelay(2000);
+               twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+                                   TWL4030_REG_ANAMICL);
+       } while ((i++ < 100) &&
+                ((byte & TWL4030_CNCL_OFFSET_START) ==
+                 TWL4030_CNCL_OFFSET_START));
+
+       /* anti-pop when changing analog gain */
+       regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+       twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+               regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
+
+       /* toggle CODECPDZ as per TRM */
+       twl4030_clear_codecpdz(codec);
+       twl4030_set_codecpdz(codec);
+
+       /* program anti-pop with bias ramp delay */
+       popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+       popn &= TWL4030_RAMP_DELAY;
+       popn |= TWL4030_RAMP_DELAY_645MS;
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+       popn |= TWL4030_VMID_EN;
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+       /* enable output stage and gain setting */
+       hsgain = TWL4030_HSR_GAIN_0DB | TWL4030_HSL_GAIN_0DB;
+       twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain);
+
+       /* enable anti-pop ramp */
+       popn |= TWL4030_RAMP_EN;
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+}
+
+static void twl4030_power_down(struct snd_soc_codec *codec)
+{
+       u8 popn, hsgain;
+
+       /* disable anti-pop ramp */
+       popn = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+       popn &= ~TWL4030_RAMP_EN;
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+       /* disable output stage and gain setting */
+       hsgain = TWL4030_HSR_GAIN_PWR_DOWN | TWL4030_HSL_GAIN_PWR_DOWN;
+       twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hsgain);
+
+       /* disable bias out */
+       popn &= ~TWL4030_VMID_EN;
+       twl4030_write(codec, TWL4030_REG_HS_POPN_SET, popn);
+
+       /* power down */
+       twl4030_clear_codecpdz(codec);
+}
+
+static int twl4030_set_bias_level(struct snd_soc_codec *codec,
+                                 enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               twl4030_power_up(codec);
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               /* TODO: develop a twl4030_prepare function */
+               break;
+       case SND_SOC_BIAS_STANDBY:
+               /* TODO: develop a twl4030_standby function */
+               twl4030_power_down(codec);
+               break;
+       case SND_SOC_BIAS_OFF:
+               twl4030_power_down(codec);
+               break;
+       }
+       codec->bias_level = level;
+
+       return 0;
+}
+
+static int twl4030_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       u8 mode, old_mode, format, old_format;
+
+
+       /* bit rate */
+       old_mode = twl4030_read_reg_cache(codec,
+                       TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+       mode = old_mode & ~TWL4030_APLL_RATE;
+
+       switch (params_rate(params)) {
+       case 8000:
+               mode |= TWL4030_APLL_RATE_8000;
+               break;
+       case 11025:
+               mode |= TWL4030_APLL_RATE_11025;
+               break;
+       case 12000:
+               mode |= TWL4030_APLL_RATE_12000;
+               break;
+       case 16000:
+               mode |= TWL4030_APLL_RATE_16000;
+               break;
+       case 22050:
+               mode |= TWL4030_APLL_RATE_22050;
+               break;
+       case 24000:
+               mode |= TWL4030_APLL_RATE_24000;
+               break;
+       case 32000:
+               mode |= TWL4030_APLL_RATE_32000;
+               break;
+       case 44100:
+               mode |= TWL4030_APLL_RATE_44100;
+               break;
+       case 48000:
+               mode |= TWL4030_APLL_RATE_48000;
+               break;
+       default:
+               printk(KERN_ERR "TWL4030 hw params: unknown rate %d\n",
+                       params_rate(params));
+               return -EINVAL;
+       }
+
+       if (mode != old_mode) {
+               /* change rate and set CODECPDZ */
+               twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+               twl4030_set_codecpdz(codec);
+       }
+
+       /* sample size */
+       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+       format = old_format;
+       format &= ~TWL4030_DATA_WIDTH;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               format |= TWL4030_DATA_WIDTH_16S_16W;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               format |= TWL4030_DATA_WIDTH_32S_24W;
+               break;
+       default:
+               printk(KERN_ERR "TWL4030 hw params: unknown format %d\n",
+                       params_format(params));
+               return -EINVAL;
+       }
+
+       if (format != old_format) {
+
+               /* clear CODECPDZ before changing format (codec requirement) */
+               twl4030_clear_codecpdz(codec);
+
+               /* change format */
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+
+               /* set CODECPDZ afterwards */
+               twl4030_set_codecpdz(codec);
+       }
+       return 0;
+}
+
+static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 infreq;
+
+       switch (freq) {
+       case 19200000:
+               infreq = TWL4030_APLL_INFREQ_19200KHZ;
+               break;
+       case 26000000:
+               infreq = TWL4030_APLL_INFREQ_26000KHZ;
+               break;
+       case 38400000:
+               infreq = TWL4030_APLL_INFREQ_38400KHZ;
+               break;
+       default:
+               printk(KERN_ERR "TWL4030 set sysclk: unknown rate %d\n",
+                       freq);
+               return -EINVAL;
+       }
+
+       infreq |= TWL4030_APLL_EN;
+       twl4030_write(codec, TWL4030_REG_APLL_CTL, infreq);
+
+       return 0;
+}
+
+static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                            unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       u8 old_format, format;
+
+       /* get format */
+       old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+       format = old_format;
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               format &= ~(TWL4030_AIF_SLAVE_EN);
+               format |= TWL4030_CLK256FS_EN;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               format &= ~(TWL4030_CLK256FS_EN);
+               format |= TWL4030_AIF_SLAVE_EN;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* interface format */
+       format &= ~TWL4030_AIF_FORMAT;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               format |= TWL4030_AIF_FORMAT_CODEC;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (format != old_format) {
+
+               /* clear CODECPDZ before changing format (codec requirement) */
+               twl4030_clear_codecpdz(codec);
+
+               /* change format */
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+
+               /* set CODECPDZ afterwards */
+               twl4030_set_codecpdz(codec);
+       }
+
+       return 0;
+}
+
+#define TWL4030_RATES   (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
+
+struct snd_soc_dai twl4030_dai = {
+       .name = "twl4030",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = TWL4030_RATES,
+               .formats = TWL4030_FORMATS,},
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = TWL4030_RATES,
+               .formats = TWL4030_FORMATS,},
+       .ops = {
+               .hw_params = twl4030_hw_params,
+       },
+       .dai_ops = {
+               .set_sysclk = twl4030_set_dai_sysclk,
+               .set_fmt = twl4030_set_dai_fmt,
+       }
+};
+EXPORT_SYMBOL_GPL(twl4030_dai);
+
+static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int twl4030_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       twl4030_set_bias_level(codec, codec->suspend_bias_level);
+       return 0;
+}
+
+/*
+ * initialize the driver
+ * register the mixer and dsp interfaces with the kernel
+ */
+
+static int twl4030_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->codec;
+       int ret = 0;
+
+       printk(KERN_INFO "TWL4030 Audio Codec init \n");
+
+       codec->name = "twl4030";
+       codec->owner = THIS_MODULE;
+       codec->read = twl4030_read_reg_cache;
+       codec->write = twl4030_write;
+       codec->set_bias_level = twl4030_set_bias_level;
+       codec->dai = &twl4030_dai;
+       codec->num_dai = 1;
+       codec->reg_cache_size = sizeof(twl4030_reg);
+       codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg),
+                                       GFP_KERNEL);
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+
+       /* register pcms */
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "twl4030: failed to create pcms\n");
+               goto pcm_err;
+       }
+
+       twl4030_init_chip(codec);
+
+       /* power on device */
+       twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       twl4030_add_controls(codec);
+       twl4030_add_widgets(codec);
+
+       ret = snd_soc_register_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "twl4030: failed to register card\n");
+               goto card_err;
+       }
+
+       return ret;
+
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       return ret;
+}
+
+static struct snd_soc_device *twl4030_socdev;
+
+static int twl4030_probe(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec;
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL)
+               return -ENOMEM;
+
+       socdev->codec = codec;
+       mutex_init(&codec->mutex);
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+
+       twl4030_socdev = socdev;
+       twl4030_init(socdev);
+
+       return 0;
+}
+
+static int twl4030_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->codec;
+
+       printk(KERN_INFO "TWL4030 Audio Codec remove\n");
+       kfree(codec);
+
+       return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_twl4030 = {
+       .probe = twl4030_probe,
+       .remove = twl4030_remove,
+       .suspend = twl4030_suspend,
+       .resume = twl4030_resume,
+};
+EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
+
+MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
+MODULE_AUTHOR("Steve Sakoman");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
new file mode 100644 (file)
index 0000000..09865d9
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * ALSA SoC TWL4030 codec driver
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TWL4030_AUDIO_H__
+#define __TWL4030_AUDIO_H__
+
+#define TWL4030_REG_CODEC_MODE         0x1
+#define TWL4030_REG_OPTION             0x2
+#define TWL4030_REG_UNKNOWN            0x3
+#define TWL4030_REG_MICBIAS_CTL                0x4
+#define TWL4030_REG_ANAMICL            0x5
+#define TWL4030_REG_ANAMICR            0x6
+#define TWL4030_REG_AVADC_CTL          0x7
+#define TWL4030_REG_ADCMICSEL          0x8
+#define TWL4030_REG_DIGMIXING          0x9
+#define TWL4030_REG_ATXL1PGA           0xA
+#define TWL4030_REG_ATXR1PGA           0xB
+#define TWL4030_REG_AVTXL2PGA          0xC
+#define TWL4030_REG_AVTXR2PGA          0xD
+#define TWL4030_REG_AUDIO_IF           0xE
+#define TWL4030_REG_VOICE_IF           0xF
+#define TWL4030_REG_ARXR1PGA           0x10
+#define TWL4030_REG_ARXL1PGA           0x11
+#define TWL4030_REG_ARXR2PGA           0x12
+#define TWL4030_REG_ARXL2PGA           0x13
+#define TWL4030_REG_VRXPGA             0x14
+#define TWL4030_REG_VSTPGA             0x15
+#define TWL4030_REG_VRX2ARXPGA         0x16
+#define TWL4030_REG_AVDAC_CTL          0x17
+#define TWL4030_REG_ARX2VTXPGA         0x18
+#define TWL4030_REG_ARXL1_APGA_CTL     0x19
+#define TWL4030_REG_ARXR1_APGA_CTL     0x1A
+#define TWL4030_REG_ARXL2_APGA_CTL     0x1B
+#define TWL4030_REG_ARXR2_APGA_CTL     0x1C
+#define TWL4030_REG_ATX2ARXPGA         0x1D
+#define TWL4030_REG_BT_IF              0x1E
+#define TWL4030_REG_BTPGA              0x1F
+#define TWL4030_REG_BTSTPGA            0x20
+#define TWL4030_REG_EAR_CTL            0x21
+#define TWL4030_REG_HS_SEL             0x22
+#define TWL4030_REG_HS_GAIN_SET                0x23
+#define TWL4030_REG_HS_POPN_SET                0x24
+#define TWL4030_REG_PREDL_CTL          0x25
+#define TWL4030_REG_PREDR_CTL          0x26
+#define TWL4030_REG_PRECKL_CTL         0x27
+#define TWL4030_REG_PRECKR_CTL         0x28
+#define TWL4030_REG_HFL_CTL            0x29
+#define TWL4030_REG_HFR_CTL            0x2A
+#define TWL4030_REG_ALC_CTL            0x2B
+#define TWL4030_REG_ALC_SET1           0x2C
+#define TWL4030_REG_ALC_SET2           0x2D
+#define TWL4030_REG_BOOST_CTL          0x2E
+#define TWL4030_REG_SOFTVOL_CTL                0x2F
+#define TWL4030_REG_DTMF_FREQSEL       0x30
+#define TWL4030_REG_DTMF_TONEXT1H      0x31
+#define TWL4030_REG_DTMF_TONEXT1L      0x32
+#define TWL4030_REG_DTMF_TONEXT2H      0x33
+#define TWL4030_REG_DTMF_TONEXT2L      0x34
+#define TWL4030_REG_DTMF_TONOFF                0x35
+#define TWL4030_REG_DTMF_WANONOFF      0x36
+#define TWL4030_REG_I2S_RX_SCRAMBLE_H  0x37
+#define TWL4030_REG_I2S_RX_SCRAMBLE_M  0x38
+#define TWL4030_REG_I2S_RX_SCRAMBLE_L  0x39
+#define TWL4030_REG_APLL_CTL           0x3A
+#define TWL4030_REG_DTMF_CTL           0x3B
+#define TWL4030_REG_DTMF_PGA_CTL2      0x3C
+#define TWL4030_REG_DTMF_PGA_CTL1      0x3D
+#define TWL4030_REG_MISC_SET_1         0x3E
+#define TWL4030_REG_PCMBTMUX           0x3F
+#define TWL4030_REG_RX_PATH_SEL                0x43
+#define TWL4030_REG_VDL_APGA_CTL       0x44
+#define TWL4030_REG_VIBRA_CTL          0x45
+#define TWL4030_REG_VIBRA_SET          0x46
+#define TWL4030_REG_VIBRA_PWM_SET      0x47
+#define TWL4030_REG_ANAMIC_GAIN                0x48
+#define TWL4030_REG_MISC_SET_2         0x49
+
+#define TWL4030_CACHEREGNUM    (TWL4030_REG_MISC_SET_2 + 1)
+
+/* Bitfield Definitions */
+
+/* TWL4030_CODEC_MODE (0x01) Fields */
+
+#define TWL4030_APLL_RATE              0xF0
+#define TWL4030_APLL_RATE_8000         0x00
+#define TWL4030_APLL_RATE_11025                0x10
+#define TWL4030_APLL_RATE_12000                0x20
+#define TWL4030_APLL_RATE_16000                0x40
+#define TWL4030_APLL_RATE_22050                0x50
+#define TWL4030_APLL_RATE_24000                0x60
+#define TWL4030_APLL_RATE_32000                0x80
+#define TWL4030_APLL_RATE_44100                0x90
+#define TWL4030_APLL_RATE_48000                0xA0
+#define TWL4030_SEL_16K                        0x04
+#define TWL4030_CODECPDZ               0x02
+#define TWL4030_OPT_MODE               0x01
+
+/* ANAMICL (0x05) Fields */
+#define TWL4030_CNCL_OFFSET_START      0x80
+#define TWL4030_OFFSET_CNCL_SEL                0x60
+#define TWL4030_OFFSET_CNCL_SEL_ARX1   0x00
+#define TWL4030_OFFSET_CNCL_SEL_ARX2   0x20
+#define TWL4030_OFFSET_CNCL_SEL_VRX    0x40
+#define TWL4030_OFFSET_CNCL_SEL_ALL    0x60
+#define TWL4030_MICAMPL_EN             0x10
+#define TWL4030_CKMIC_EN               0x08
+#define TWL4030_AUXL_EN                        0x04
+#define TWL4030_HSMIC_EN               0x02
+#define TWL4030_MAINMIC_EN             0x01
+
+/* ANAMICR (0x06) Fields */
+#define TWL4030_MICAMPR_EN             0x10
+#define TWL4030_AUXR_EN                        0x04
+#define TWL4030_SUBMIC_EN              0x01
+
+/* AUDIO_IF (0x0E) Fields */
+
+#define TWL4030_AIF_SLAVE_EN           0x80
+#define TWL4030_DATA_WIDTH             0x60
+#define TWL4030_DATA_WIDTH_16S_16W     0x00
+#define TWL4030_DATA_WIDTH_32S_16W     0x40
+#define TWL4030_DATA_WIDTH_32S_24W     0x60
+#define TWL4030_AIF_FORMAT             0x18
+#define TWL4030_AIF_FORMAT_CODEC       0x00
+#define TWL4030_AIF_FORMAT_LEFT                0x08
+#define TWL4030_AIF_FORMAT_RIGHT       0x10
+#define TWL4030_AIF_FORMAT_TDM         0x18
+#define TWL4030_AIF_TRI_EN             0x04
+#define TWL4030_CLK256FS_EN            0x02
+#define TWL4030_AIF_EN                 0x01
+
+/* HS_GAIN_SET (0x23) Fields */
+
+#define TWL4030_HSR_GAIN               0x0C
+#define TWL4030_HSR_GAIN_PWR_DOWN      0x00
+#define TWL4030_HSR_GAIN_PLUS_6DB      0x04
+#define TWL4030_HSR_GAIN_0DB           0x08
+#define TWL4030_HSR_GAIN_MINUS_6DB     0x0C
+#define TWL4030_HSL_GAIN               0x03
+#define TWL4030_HSL_GAIN_PWR_DOWN      0x00
+#define TWL4030_HSL_GAIN_PLUS_6DB      0x01
+#define TWL4030_HSL_GAIN_0DB           0x02
+#define TWL4030_HSL_GAIN_MINUS_6DB     0x03
+
+/* HS_POPN_SET (0x24) Fields */
+
+#define TWL4030_VMID_EN                        0x40
+#define        TWL4030_EXTMUTE                 0x20
+#define TWL4030_RAMP_DELAY             0x1C
+#define TWL4030_RAMP_DELAY_20MS                0x00
+#define TWL4030_RAMP_DELAY_40MS                0x04
+#define TWL4030_RAMP_DELAY_81MS                0x08
+#define TWL4030_RAMP_DELAY_161MS       0x0C
+#define TWL4030_RAMP_DELAY_323MS       0x10
+#define TWL4030_RAMP_DELAY_645MS       0x14
+#define TWL4030_RAMP_DELAY_1291MS      0x18
+#define TWL4030_RAMP_DELAY_2581MS      0x1C
+#define TWL4030_RAMP_EN                        0x02
+
+/* APLL_CTL (0x3A) Fields */
+
+#define TWL4030_APLL_EN                        0x10
+#define TWL4030_APLL_INFREQ            0x0F
+#define TWL4030_APLL_INFREQ_19200KHZ   0x05
+#define TWL4030_APLL_INFREQ_26000KHZ   0x06
+#define TWL4030_APLL_INFREQ_38400KHZ   0x0F
+
+/* REG_MISC_SET_1 (0x3E) Fields */
+
+#define TWL4030_CLK64_EN               0x80
+#define TWL4030_SCRAMBLE_EN            0x40
+#define TWL4030_FMLOOP_EN              0x20
+#define TWL4030_SMOOTH_ANAVOL_EN       0x02
+#define TWL4030_DIGMIC_LR_SWAP_EN      0x01
+
+extern struct snd_soc_dai twl4030_dai;
+extern struct snd_soc_codec_device soc_codec_dev_twl4030;
+
+#endif /* End of __TWL4030_AUDIO_H__ */
index aea27e70043cf8f687884227c117ceed224c98f4..d7b8939dee58f756450aa593ce8ead5625ec50ca 100644 (file)
@@ -13,3 +13,12 @@ config SND_OMAP_SOC_N810
        select SND_SOC_TLV320AIC3X
        help
          Say Y if you want to add support for SoC audio on Nokia N810.
+
+config SND_OMAP_SOC_OVERO
+       tristate "SoC Audio support for Gumstix Overo"
+       depends on SND_OMAP_SOC && MACH_OVERO
+       select SND_OMAP_SOC_MCBSP
+       select SND_SOC_TWL4030
+       help
+         Say Y if you want to add support for SoC audio on the Gumstix Overo.
+
index d8d8d58075e3ee4c0b362eadeee9fce1b43cc2d3..b96b97b3435cc3b35692fcb68dcb1435b0ef27ce 100644 (file)
@@ -7,5 +7,8 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
 
 # OMAP Machine Support
 snd-soc-n810-objs := n810.o
+snd-soc-overo-objs := overo.o
 
 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
+obj-$(CONFIG_SND_OMAP_SOC_OVERO) += snd-soc-overo.o
+
index 35310e16d7f3658623fdf9755ae6df7190688a1e..3a4cc4bed368c4cf88a04fc9dbaa168942dee897 100644 (file)
@@ -84,11 +84,22 @@ static const unsigned long omap1_mcbsp_port[][2] = {
 static const int omap1_dma_reqs[][2] = {};
 static const unsigned long omap1_mcbsp_port[][2] = {};
 #endif
-#if defined(CONFIG_ARCH_OMAP2420)
-static const int omap2420_dma_reqs[][2] = {
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+static const int omap24xx_dma_reqs[][2] = {
        { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
        { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
+       { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX },
+       { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX },
+       { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX },
+#endif
 };
+#else
+static const int omap24xx_dma_reqs[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP2420)
 static const unsigned long omap2420_mcbsp_port[][2] = {
        { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
          OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
@@ -96,10 +107,43 @@ static const unsigned long omap2420_mcbsp_port[][2] = {
          OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
 };
 #else
-static const int omap2420_dma_reqs[][2] = {};
 static const unsigned long omap2420_mcbsp_port[][2] = {};
 #endif
 
+#if defined(CONFIG_ARCH_OMAP2430)
+static const unsigned long omap2430_mcbsp_port[][2] = {
+       { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP2430_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap2430_mcbsp_port[][2] = {};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const unsigned long omap34xx_mcbsp_port[][2] = {
+       { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP3_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP4_BASE + OMAP_MCBSP_REG_DRR },
+       { OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DXR,
+         OMAP34XX_MCBSP5_BASE + OMAP_MCBSP_REG_DRR },
+};
+#else
+static const unsigned long omap34xx_mcbsp_port[][2] = {};
+#endif
+
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -167,12 +211,15 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                dma = omap1_dma_reqs[bus_id][substream->stream];
                port = omap1_mcbsp_port[bus_id][substream->stream];
        } else if (cpu_is_omap2420()) {
-               dma = omap2420_dma_reqs[bus_id][substream->stream];
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
                port = omap2420_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap2430()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap2430_mcbsp_port[bus_id][substream->stream];
+       } else if (cpu_is_omap343x()) {
+               dma = omap24xx_dma_reqs[bus_id][substream->stream];
+               port = omap34xx_mcbsp_port[bus_id][substream->stream];
        } else {
-               /*
-                * TODO: Add support for 2430 and 3430
-                */
                return -ENODEV;
        }
        omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
@@ -310,7 +357,7 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                                       int clk_id)
 {
        int sel_bit;
-       u16 reg;
+       u16 reg, reg_devconf1 = OMAP243X_CONTROL_DEVCONF1;
 
        if (cpu_class_is_omap1()) {
                /* OMAP1's can use only external source clock */
@@ -320,6 +367,12 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                        return 0;
        }
 
+       if (cpu_is_omap2420() && mcbsp_data->bus_id > 1)
+               return -EINVAL;
+
+       if (cpu_is_omap343x())
+               reg_devconf1 = OMAP343X_CONTROL_DEVCONF1;
+
        switch (mcbsp_data->bus_id) {
        case 0:
                reg = OMAP2_CONTROL_DEVCONF0;
@@ -329,20 +382,26 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
                reg = OMAP2_CONTROL_DEVCONF0;
                sel_bit = 6;
                break;
-       /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+       case 2:
+               reg = reg_devconf1;
+               sel_bit = 0;
+               break;
+       case 3:
+               reg = reg_devconf1;
+               sel_bit = 2;
+               break;
+       case 4:
+               reg = reg_devconf1;
+               sel_bit = 4;
+               break;
        default:
                return -EINVAL;
        }
 
-       if (cpu_class_is_omap2()) {
-               if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) &
-                                        ~(1 << sel_bit), reg);
-               } else {
-                       omap_ctrl_writel(omap_ctrl_readl(reg) |
-                                        (1 << sel_bit), reg);
-               }
-       }
+       if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK)
+               omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg);
+       else
+               omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg);
 
        return 0;
 }
diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c
new file mode 100644 (file)
index 0000000..c26d1de
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * overo.c  --  SoC audio for Gumstix Overo
+ *
+ * Author: Steve Sakoman <steve@sakoman.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+#include <mach/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/twl4030.h"
+
+static int overo_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       int ret;
+
+       /* Set codec DAI configuration */
+       ret = snd_soc_dai_set_fmt(codec_dai,
+                                 SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec DAI configuration\n");
+               return ret;
+       }
+
+       /* Set cpu DAI configuration */
+       ret = snd_soc_dai_set_fmt(cpu_dai,
+                                 SND_SOC_DAIFMT_I2S |
+                                 SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set cpu DAI configuration\n");
+               return ret;
+       }
+
+       /* Set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+                                           SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               printk(KERN_ERR "can't set codec system clock\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops overo_ops = {
+       .hw_params = overo_hw_params,
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link overo_dai = {
+       .name = "TWL4030",
+       .stream_name = "TWL4030",
+       .cpu_dai = &omap_mcbsp_dai[0],
+       .codec_dai = &twl4030_dai,
+       .ops = &overo_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_overo = {
+       .name = "overo",
+       .dai_link = &overo_dai,
+       .num_links = 1,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device overo_snd_devdata = {
+       .machine = &snd_soc_machine_overo,
+       .platform = &omap_soc_platform,
+       .codec_dev = &soc_codec_dev_twl4030,
+};
+
+static struct platform_device *overo_snd_device;
+
+static int __init overo_soc_init(void)
+{
+       int ret;
+
+       if (!machine_is_overo()) {
+               pr_debug("Not Overo!\n");
+               return -ENODEV;
+       }
+       printk(KERN_INFO "overo SoC init\n");
+
+       overo_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!overo_snd_device) {
+               printk(KERN_ERR "Platform device allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(overo_snd_device, &overo_snd_devdata);
+       overo_snd_devdata.dev = &overo_snd_device->dev;
+       *(unsigned int *)overo_dai.cpu_dai->private_data = 1; /* McBSP2 */
+
+       ret = platform_device_add(overo_snd_device);
+       if (ret)
+               goto err1;
+
+       return 0;
+
+err1:
+       printk(KERN_ERR "Unable to add platform device\n");
+       platform_device_put(overo_snd_device);
+
+       return ret;
+}
+module_init(overo_soc_init);
+
+static void __exit overo_soc_exit(void)
+{
+       platform_device_unregister(overo_snd_device);
+}
+module_exit(overo_soc_exit);
+
+MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
+MODULE_DESCRIPTION("ALSA SoC overo");
+MODULE_LICENSE("GPL");